From 154c7182919ba2afbf4ec2f846fa6e385fbcf14f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Oct 2025 12:52:48 -0700 Subject: [PATCH] Export data addresses from the Wasm module just like other symbols. This removes the special handling of exported immutable globals which simplifies the code in a few different ways. For programs that export data addresses (this is relatively rare) this means codesize reduction for the generated JS (since it no longer contains the constant values) and the codesize increase for the Wasm binary (since it now contains extra exports). The main reason for this is consistency with dynamic linking (where data exports are always needed) and a reduction in complexity. Fixes: #25556 --- src/lib/libcore.js | 18 +++--- src/lib/libdylink.js | 21 ++++--- src/preamble.js | 7 +-- src/settings_internal.js | 3 - test/codesize/test_codesize_hello_dylink.json | 8 +-- .../test_codesize_hello_dylink_all.json | 4 +- test/codesize/test_codesize_minimal_64.json | 15 ++--- .../test_codesize_minimal_O0.expected.js | 5 +- test/codesize/test_codesize_minimal_O0.json | 8 +-- test/codesize/test_codesize_minimal_O1.json | 8 +-- test/codesize/test_codesize_minimal_O2.json | 4 +- test/codesize/test_codesize_minimal_O3.json | 13 +++-- test/codesize/test_codesize_minimal_Os.json | 13 +++-- .../codesize/test_codesize_minimal_Os_mr.json | 11 ++-- .../test_codesize_minimal_Oz-ctors.json | 13 +++-- test/codesize/test_codesize_minimal_Oz.json | 13 +++-- test/codesize/test_codesize_minimal_esm.json | 15 ++--- .../test_codesize_minimal_pthreads.json | 41 +++++++------- ...t_codesize_minimal_pthreads_memgrowth.json | 41 +++++++------- .../test_codesize_minimal_wasmfs.json | 13 +++-- test/test_core.py | 1 - tools/building.py | 16 +----- tools/emscripten.py | 56 ++++++------------- tools/extract_metadata.py | 26 ++------- 24 files changed, 167 insertions(+), 206 deletions(-) diff --git a/src/lib/libcore.js b/src/lib/libcore.js index 64d153ebbd826..f3b042033f3ca 100644 --- a/src/lib/libcore.js +++ b/src/lib/libcore.js @@ -1632,16 +1632,20 @@ addToLibrary({ dynCalls[name.substr(8)] = exportedSymbol; } #endif - // Globals are currently statically enumerated into the output JS. - // TODO: If the number of Globals grows large, consider giving them a - // similar DECLARE_ASM_MODULE_EXPORTS = 0 treatment. - if (typeof exportedSymbol.value === 'undefined') { -#if MINIMAL_RUNTIME - globalThis[name] = exportedSymbol; + // Special handling for Wasm globals. See `create_receiving` for the + // static version of this code. + if (typeof exportedSymbol.value != 'undefined') { +#if MEMORY64 + exportedSymbol = Number(exportedSymbol.value); #else - globalThis[name] = Module[name] = exportedSymbol; + exportedSymbol = exportedSymbol.value #endif } +#if MINIMAL_RUNTIME + globalThis[name] = exportedSymbol; +#else + globalThis[name] = Module[name] = exportedSymbol; +#endif } exportAliases(wasmExports); }, diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index 9f45e32cb9900..d5e80250f06da 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -249,7 +249,7 @@ var LibraryDylink = { var newValue; if (typeof value == 'function') { newValue = {{{ to64('addFunction(value)') }}}; - } else if (typeof value == {{{ POINTER_JS_TYPE }}}) { + } else if (typeof value.value == {{{ POINTER_JS_TYPE }}}) { newValue = value; } else { // The GOT can only contain addresses (i.e data addresses or function @@ -306,7 +306,7 @@ var LibraryDylink = { // Detect immuable wasm global exports. These represent data addresses // which are relative to `memoryBase` if (isImmutableGlobal(value)) { - return value.value + {{{ to64('memoryBase') }}}; + return new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}'}, value.value + {{{ to64('memoryBase') }}}); } // Return unmodified value (no relocation required). @@ -354,10 +354,8 @@ var LibraryDylink = { #endif } else if (typeof value == 'number') { entry.value = {{{ to64('value') }}}; -#if MEMORY64 - } else if (typeof value == 'bigint') { + } else if (typeof value.value == {{{ POINTER_JS_TYPE }}}) { entry.value = value; -#endif } else { throw new Error(`bad export type for '${symName}': ${typeof value} (${value})`); } @@ -422,6 +420,8 @@ var LibraryDylink = { // Keep __heap_base stack aligned. var end = ret + alignMemory(size, {{{ STACK_ALIGN }}}); #if ASSERTIONS + //dbg(ret); + //dbg(HEAP8.length); assert(end <= HEAP8.length, 'failure to getMemory - memory growth etc. is not supported there, call malloc/sbrk directly or increase INITIAL_MEMORY'); #endif ___heap_base = end; @@ -859,10 +859,15 @@ var LibraryDylink = { // Add any EM_ASM function that exist in the side module if ('__start_em_asm' in moduleExports) { - var start = moduleExports['__start_em_asm']; - var stop = moduleExports['__stop_em_asm']; + var start = moduleExports['__start_em_asm'].value; + var stop = moduleExports['__stop_em_asm'].value; +#if CAN_ADDRESS_2GB + start >>>= 0; + stop >>>= 0; +#else {{{ from64('start') }}} {{{ from64('stop') }}} +#endif while (start < stop) { var jsString = UTF8ToString(start); addEmAsm(start, jsString); @@ -892,7 +897,7 @@ var LibraryDylink = { for (var name in moduleExports) { if (name.startsWith('__em_js__')) { - var start = moduleExports[name] + var start = moduleExports[name].value var jsString = UTF8ToString({{{ from64Expr('start') }}}); // EM_JS strings are stored in the data section in the form // SIG<::>BODY. diff --git a/src/preamble.js b/src/preamble.js index c54ec203849bc..1df464281ee21 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -719,13 +719,10 @@ function getWasmImports() { wasmExports = instance.exports; #if MAIN_MODULE - // No relocation needed here.. but calling this just so that updateGOT is - // called. #if RELOCATABLE - var origExports = wasmExports = relocateExports(wasmExports, {{{ GLOBAL_BASE }}}); -#else - var origExports = wasmExports = relocateExports(wasmExports); + wasmExports = relocateExports(wasmExports, {{{ GLOBAL_BASE }}}); #endif + var origExports = wasmExports; #endif #if ASYNCIFY diff --git a/src/settings_internal.js b/src/settings_internal.js index 44f4e68830918..0932bf6519db7 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -16,9 +16,6 @@ // underscore. var WASM_EXPORTS = []; -// Similar to above but only includes the data symbols (address exports). -var DATA_EXPORTS = []; - // An array of all symbols exported from all the side modules specified on the // command line. // These are raw symbol names and are not mangled to include the leading diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index cb91373404ba7..ba92f4bbde804 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -1,10 +1,10 @@ { - "a.out.js": 26549, - "a.out.js.gz": 11353, + "a.out.js": 26672, + "a.out.js.gz": 11377, "a.out.nodebug.wasm": 17761, "a.out.nodebug.wasm.gz": 8991, - "total": 44310, - "total_gz": 20344, + "total": 44433, + "total_gz": 20368, "sent": [ "__syscall_stat64", "emscripten_resize_heap", diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index cf225582ad220..5dd7e9825e044 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,7 +1,7 @@ { - "a.out.js": 245302, + "a.out.js": 245421, "a.out.nodebug.wasm": 574167, - "total": 819469, + "total": 819588, "sent": [ "IMG_Init", "IMG_Load", diff --git a/test/codesize/test_codesize_minimal_64.json b/test/codesize/test_codesize_minimal_64.json index 292fc4a2712b0..2fcaae6dada80 100644 --- a/test/codesize/test_codesize_minimal_64.json +++ b/test/codesize/test_codesize_minimal_64.json @@ -1,16 +1,17 @@ { - "a.out.js": 2595, - "a.out.js.gz": 1243, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2657, - "total_gz": 1319, + "a.out.js": 2604, + "a.out.js.gz": 1247, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 88, + "total": 2679, + "total_gz": 1335, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_O0.expected.js b/test/codesize/test_codesize_minimal_O0.expected.js index dfaa790afb4ce..7df50c3cb230d 100644 --- a/test/codesize/test_codesize_minimal_O0.expected.js +++ b/test/codesize/test_codesize_minimal_O0.expected.js @@ -1323,6 +1323,7 @@ var __emscripten_stack_restore = makeInvalidEarlyAccess('__emscripten_stack_rest var __emscripten_stack_alloc = makeInvalidEarlyAccess('__emscripten_stack_alloc'); var _emscripten_stack_get_current = makeInvalidEarlyAccess('_emscripten_stack_get_current'); var memory = makeInvalidEarlyAccess('memory'); +var _global_val = Module['_global_val'] = makeInvalidEarlyAccess('_global_val'); var __indirect_function_table = makeInvalidEarlyAccess('__indirect_function_table'); var wasmMemory = makeInvalidEarlyAccess('wasmMemory'); @@ -1347,12 +1348,12 @@ function assignWasmExports(wasmExports) { _emscripten_stack_get_current = wasmExports['emscripten_stack_get_current']; assert(typeof wasmExports['memory'] != 'undefined', 'missing Wasm export: memory'); memory = wasmMemory = wasmExports['memory']; + assert(typeof wasmExports['global_val'] != 'undefined', 'missing Wasm export: global_val'); + _global_val = Module['_global_val'] = wasmExports['global_val'].value; assert(typeof wasmExports['__indirect_function_table'] != 'undefined', 'missing Wasm export: __indirect_function_table'); __indirect_function_table = wasmExports['__indirect_function_table']; } -var _global_val = Module['_global_val'] = 65536; - var wasmImports = { }; diff --git a/test/codesize/test_codesize_minimal_O0.json b/test/codesize/test_codesize_minimal_O0.json index a78c3e2b97ea3..f1335a09ac0b8 100644 --- a/test/codesize/test_codesize_minimal_O0.json +++ b/test/codesize/test_codesize_minimal_O0.json @@ -1,10 +1,10 @@ { - "a.out.js": 19364, - "a.out.js.gz": 6998, + "a.out.js": 19489, + "a.out.js.gz": 7016, "a.out.nodebug.wasm": 1136, "a.out.nodebug.wasm.gz": 659, - "total": 20500, - "total_gz": 7657, + "total": 20625, + "total_gz": 7675, "sent": [], "imports": [], "exports": [ diff --git a/test/codesize/test_codesize_minimal_O1.json b/test/codesize/test_codesize_minimal_O1.json index e4ce9e092f637..392b4ac27d486 100644 --- a/test/codesize/test_codesize_minimal_O1.json +++ b/test/codesize/test_codesize_minimal_O1.json @@ -1,10 +1,10 @@ { - "a.out.js": 3049, - "a.out.js.gz": 1301, + "a.out.js": 3061, + "a.out.js.gz": 1300, "a.out.nodebug.wasm": 449, "a.out.nodebug.wasm.gz": 337, - "total": 3498, - "total_gz": 1638, + "total": 3510, + "total_gz": 1637, "sent": [], "imports": [], "exports": [ diff --git a/test/codesize/test_codesize_minimal_O2.json b/test/codesize/test_codesize_minimal_O2.json index a540670ec74ae..afc724bf811ee 100644 --- a/test/codesize/test_codesize_minimal_O2.json +++ b/test/codesize/test_codesize_minimal_O2.json @@ -1,9 +1,9 @@ { - "a.out.js": 2342, + "a.out.js": 2352, "a.out.js.gz": 1171, "a.out.nodebug.wasm": 280, "a.out.nodebug.wasm.gz": 226, - "total": 2622, + "total": 2632, "total_gz": 1397, "sent": [], "imports": [], diff --git a/test/codesize/test_codesize_minimal_O3.json b/test/codesize/test_codesize_minimal_O3.json index d8f58f65303ad..b7ab6c28df39a 100644 --- a/test/codesize/test_codesize_minimal_O3.json +++ b/test/codesize/test_codesize_minimal_O3.json @@ -1,16 +1,17 @@ { - "a.out.js": 2292, + "a.out.js": 2293, "a.out.js.gz": 1137, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2354, - "total_gz": 1213, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 2368, + "total_gz": 1224, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_Os.json b/test/codesize/test_codesize_minimal_Os.json index d8f58f65303ad..b7ab6c28df39a 100644 --- a/test/codesize/test_codesize_minimal_Os.json +++ b/test/codesize/test_codesize_minimal_Os.json @@ -1,16 +1,17 @@ { - "a.out.js": 2292, + "a.out.js": 2293, "a.out.js.gz": 1137, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2354, - "total_gz": 1213, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 2368, + "total_gz": 1224, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_Os_mr.json b/test/codesize/test_codesize_minimal_Os_mr.json index f000318e8ad07..ba8b6e7923c80 100644 --- a/test/codesize/test_codesize_minimal_Os_mr.json +++ b/test/codesize/test_codesize_minimal_Os_mr.json @@ -1,16 +1,17 @@ { "a.out.js": 497, "a.out.js.gz": 297, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 559, - "total_gz": 373, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 572, + "total_gz": 384, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_Oz-ctors.json b/test/codesize/test_codesize_minimal_Oz-ctors.json index 9dd3195eee2ab..d60fdef1cca9b 100644 --- a/test/codesize/test_codesize_minimal_Oz-ctors.json +++ b/test/codesize/test_codesize_minimal_Oz-ctors.json @@ -1,15 +1,16 @@ { - "a.out.js": 2271, + "a.out.js": 2272, "a.out.js.gz": 1122, - "a.out.nodebug.wasm": 51, - "a.out.nodebug.wasm.gz": 68, - "total": 2322, - "total_gz": 1190, + "a.out.nodebug.wasm": 64, + "a.out.nodebug.wasm.gz": 80, + "total": 2336, + "total_gz": 1202, "sent": [], "imports": [], "exports": [ "a (memory)", - "b (add)" + "b (add)", + "c (global_val)" ], "funcs": [ "$add" diff --git a/test/codesize/test_codesize_minimal_Oz.json b/test/codesize/test_codesize_minimal_Oz.json index d8f58f65303ad..b7ab6c28df39a 100644 --- a/test/codesize/test_codesize_minimal_Oz.json +++ b/test/codesize/test_codesize_minimal_Oz.json @@ -1,16 +1,17 @@ { - "a.out.js": 2292, + "a.out.js": 2293, "a.out.js.gz": 1137, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2354, - "total_gz": 1213, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 2368, + "total_gz": 1224, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_esm.json b/test/codesize/test_codesize_minimal_esm.json index 7bef5a7776a18..71dc359fe1e37 100644 --- a/test/codesize/test_codesize_minimal_esm.json +++ b/test/codesize/test_codesize_minimal_esm.json @@ -1,16 +1,17 @@ { - "a.out.js": 2427, - "a.out.js.gz": 1169, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2489, - "total_gz": 1245, + "a.out.js": 2429, + "a.out.js.gz": 1168, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 2504, + "total_gz": 1255, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 5287655f2d28c..7e1fd0654f537 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -1,10 +1,10 @@ { - "a.out.js": 7609, - "a.out.js.gz": 3762, - "a.out.nodebug.wasm": 19605, - "a.out.nodebug.wasm.gz": 9063, - "total": 27214, - "total_gz": 12825, + "a.out.js": 7611, + "a.out.js.gz": 3764, + "a.out.nodebug.wasm": 19615, + "a.out.nodebug.wasm.gz": 9071, + "total": 27226, + "total_gz": 12835, "sent": [ "a (memory)", "b (emscripten_get_now)", @@ -40,23 +40,24 @@ "o (__pthread_create_js)" ], "exports": [ - "A (_emscripten_thread_exit)", - "B (_emscripten_check_mailbox)", - "C (emscripten_stack_set_limits)", - "D (_emscripten_stack_restore)", - "E (_emscripten_stack_alloc)", - "F (emscripten_stack_get_current)", + "A (_emscripten_thread_free_data)", + "B (_emscripten_thread_exit)", + "C (_emscripten_check_mailbox)", + "D (emscripten_stack_set_limits)", + "E (_emscripten_stack_restore)", + "F (_emscripten_stack_alloc)", + "G (emscripten_stack_get_current)", "p (__wasm_call_ctors)", "q (add)", "r (main)", - "s (__indirect_function_table)", - "t (_emscripten_tls_init)", - "u (pthread_self)", - "v (_emscripten_proxy_main)", - "w (_emscripten_thread_init)", - "x (_emscripten_thread_crashed)", - "y (_emscripten_run_js_on_main_thread)", - "z (_emscripten_thread_free_data)" + "s (global_val)", + "t (__indirect_function_table)", + "u (_emscripten_tls_init)", + "v (pthread_self)", + "w (_emscripten_proxy_main)", + "x (_emscripten_thread_init)", + "y (_emscripten_thread_crashed)", + "z (_emscripten_run_js_on_main_thread)" ], "funcs": [ "$__emscripten_stdout_seek", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index abb13ded1bd90..6ed6c51ed12be 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -1,10 +1,10 @@ { - "a.out.js": 8036, - "a.out.js.gz": 3962, - "a.out.nodebug.wasm": 19606, - "a.out.nodebug.wasm.gz": 9064, - "total": 27642, - "total_gz": 13026, + "a.out.js": 8038, + "a.out.js.gz": 3964, + "a.out.nodebug.wasm": 19616, + "a.out.nodebug.wasm.gz": 9071, + "total": 27654, + "total_gz": 13035, "sent": [ "a (memory)", "b (emscripten_get_now)", @@ -40,23 +40,24 @@ "o (__pthread_create_js)" ], "exports": [ - "A (_emscripten_thread_exit)", - "B (_emscripten_check_mailbox)", - "C (emscripten_stack_set_limits)", - "D (_emscripten_stack_restore)", - "E (_emscripten_stack_alloc)", - "F (emscripten_stack_get_current)", + "A (_emscripten_thread_free_data)", + "B (_emscripten_thread_exit)", + "C (_emscripten_check_mailbox)", + "D (emscripten_stack_set_limits)", + "E (_emscripten_stack_restore)", + "F (_emscripten_stack_alloc)", + "G (emscripten_stack_get_current)", "p (__wasm_call_ctors)", "q (add)", "r (main)", - "s (__indirect_function_table)", - "t (_emscripten_tls_init)", - "u (pthread_self)", - "v (_emscripten_proxy_main)", - "w (_emscripten_thread_init)", - "x (_emscripten_thread_crashed)", - "y (_emscripten_run_js_on_main_thread)", - "z (_emscripten_thread_free_data)" + "s (global_val)", + "t (__indirect_function_table)", + "u (_emscripten_tls_init)", + "v (pthread_self)", + "w (_emscripten_proxy_main)", + "x (_emscripten_thread_init)", + "y (_emscripten_thread_crashed)", + "z (_emscripten_run_js_on_main_thread)" ], "funcs": [ "$__emscripten_stdout_seek", diff --git a/test/codesize/test_codesize_minimal_wasmfs.json b/test/codesize/test_codesize_minimal_wasmfs.json index d8f58f65303ad..b7ab6c28df39a 100644 --- a/test/codesize/test_codesize_minimal_wasmfs.json +++ b/test/codesize/test_codesize_minimal_wasmfs.json @@ -1,16 +1,17 @@ { - "a.out.js": 2292, + "a.out.js": 2293, "a.out.js.gz": 1137, - "a.out.nodebug.wasm": 62, - "a.out.nodebug.wasm.gz": 76, - "total": 2354, - "total_gz": 1213, + "a.out.nodebug.wasm": 75, + "a.out.nodebug.wasm.gz": 87, + "total": 2368, + "total_gz": 1224, "sent": [], "imports": [], "exports": [ "a (memory)", "b (__wasm_call_ctors)", - "c (add)" + "c (add)", + "d (global_val)" ], "funcs": [ "$__wasm_call_ctors", diff --git a/test/test_core.py b/test/test_core.py index eb03a3aac0305..40431c8dc4118 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9725,7 +9725,6 @@ def test_externref_emjs(self, dynlink): 'dylink': [True], }) @no_esm_integration('https://github.com/emscripten-core/emscripten/issues/25543') - @no_omit_asm_module_exports('https://github.com/emscripten-core/emscripten/issues/25556') def test_wasm_global(self, dynlink): if '-flto' in self.cflags or '-flto=thin' in self.cflags: self.skipTest('https://github.com/emscripten-core/emscripten/issues/25555') diff --git a/tools/building.py b/tools/building.py index 984daf3e71f06..5087597fb510e 100644 --- a/tools/building.py +++ b/tools/building.py @@ -821,21 +821,7 @@ def get_last_binaryen_opts(): def metadce(js_file, wasm_file, debug_info, last): logger.debug('running meta-DCE') temp_files = shared.get_temp_files() - # first, get the JS part of the graph - if settings.MAIN_MODULE: - # For the main module we include all exports as possible roots, not just function exports. - # This means that any usages of data symbols within the JS or in the side modules can/will keep - # these exports alive on the wasm module. - # This is important today for weak data symbols that are defined by the main and the side module - # (i.e. RTTI info). We want to make sure the main module's symbols get added to wasmImports - # when the main module is loaded. If this doesn't happen then the symbols in the side module - # will take precedence. - exports = settings.WASM_EXPORTS - else: - # Ignore exported wasm globals. Those get inlined directly into the JS code. - exports = sorted(set(settings.WASM_EXPORTS) - set(settings.DATA_EXPORTS)) - - extra_info = {"exports": [[asmjs_mangle(x), x] for x in exports]} + extra_info = {"exports": [[asmjs_mangle(x), x] for x in settings.WASM_EXPORTS]} txt = acorn_optimizer(js_file, ['emitDCEGraph', '--no-print'], return_output=True, extra_info=extra_info) if shared.SKIP_SUBPROCS: diff --git a/tools/emscripten.py b/tools/emscripten.py index a94b2401dde96..820b575f767e8 100644 --- a/tools/emscripten.py +++ b/tools/emscripten.py @@ -112,7 +112,6 @@ def update_settings_glue(wasm_file, metadata, base_metadata): settings.WASM_EXPORTS = base_metadata.all_exports else: settings.WASM_EXPORTS = metadata.all_exports - settings.DATA_EXPORTS = list(metadata.data_exports.keys()) settings.HAVE_EM_ASM = bool(settings.MAIN_MODULE or len(metadata.em_asm_consts) != 0) # start with the MVP features, and add any detected features. @@ -270,30 +269,6 @@ def trim_asm_const_body(body): return body -def create_data_exports(data_exports): - lines = [] - for k, v in data_exports.items(): - if shared.is_internal_global(k): - continue - - v = int(v) - - if not settings.MEMORY64: - # We assume that global exports are addresses, which need to be interpreted as unsigned. - # This is not necessary (and does not work) under wasm64 when the globals are i64. - v = v & 0xFFFFFFFF - - if settings.RELOCATABLE: - v += settings.GLOBAL_BASE - mangled = asmjs_mangle(k) - if should_export(mangled) and not settings.MINIMAL_RUNTIME: - lines.append("var %s = Module['%s'] = %s;" % (mangled, mangled, v)) - else: - lines.append("var %s = %s;" % (mangled, v)) - - return '\n'.join(lines) - - def emscript(in_wasm, out_wasm, outfile_js, js_syms, finalize=True, base_metadata=None): # Overview: # * Run wasm-emscripten-finalize to extract metadata and modify the binary @@ -407,13 +382,11 @@ def emscript(in_wasm, out_wasm, outfile_js, js_syms, finalize=True, base_metadat if base_metadata: function_exports = base_metadata.function_exports other_exports = base_metadata.other_exports - # We want the real values from the final metadata but we only want to - # include names from the base_metadata. See phase_link() in link.py. - data_exports = {k: v for k, v in metadata.data_exports.items() if k in base_metadata.data_exports} else: function_exports = metadata.function_exports other_exports = metadata.other_exports - data_exports = metadata.data_exports + + other_exports = [e for e in other_exports if not shared.is_internal_global(e[0].name)] if settings.ASYNCIFY == 1: function_exports['asyncify_start_unwind'] = webassembly.FuncType([webassembly.Type.I32], []) @@ -422,7 +395,7 @@ def emscript(in_wasm, out_wasm, outfile_js, js_syms, finalize=True, base_metadat function_exports['asyncify_stop_rewind'] = webassembly.FuncType([], []) parts = [pre] - parts += create_module(metadata, function_exports, data_exports, other_exports, + parts += create_module(metadata, function_exports, other_exports, forwarded_json['librarySymbols'], forwarded_json['nativeAliases']) parts.append(post) settings.ALIASES = list(forwarded_json['nativeAliases'].keys()) @@ -915,7 +888,7 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): receiving = ['\n// Imports from the Wasm binary.'] if settings.WASM_ESM_INTEGRATION: - exported_symbols = other_exports + list(function_exports.keys()) + exported_symbols = [e[0].name for e in other_exports] + list(function_exports.keys()) exports = [] for sym in exported_symbols: mangled = asmjs_mangle(sym) @@ -952,8 +925,8 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): # function assignWasmExports(wasmExport) { # _main = wasmExports["_main"]; exports = {name: sig for name, sig in function_exports.items() if name != building.WASM_CALL_CTORS} - for name in other_exports: - exports[name] = None + for export, info in other_exports: + exports[export.name] = (export, info) mangled = [asmjs_mangle(s) for s in exports] + list(aliases.keys()) if settings.ASSERTIONS: @@ -984,8 +957,8 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): do_module_exports = (settings.MODULARIZE or not settings.MINIMAL_RUNTIME) and settings.MODULARIZE != 'instance' receiving.append('\nfunction assignWasmExports(wasmExports) {') - for sym, sig in exports.items(): - is_function = sig is not None + for sym, info in exports.items(): + is_function = type(info) == webassembly.FuncType mangled = asmjs_mangle(sym) assignment = mangled if generate_dyncall_assignment and is_function and sym.startswith('dynCall_'): @@ -1001,8 +974,16 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): if do_module_exports and target in settings.EXPORTED_RUNTIME_METHODS: assignment += f" = Module['{target}']" if is_function and install_debug_wrapper(sym): - nargs = len(sig.params) + nargs = len(info.params) receiving.append(f" {assignment} = createExportWrapper('{sym}', {nargs});") + elif not is_function and info[0].kind == webassembly.ExternType.GLOBAL and not info[1].mutable: + if settings.LEGACY_VM_SUPPORT: + value = f"typeof wasmExports['{sym}'] == 'object' ? wasmExports['{sym}'].value : wasmExports['{sym}']" + else: + value = f"wasmExports['{sym}'].value" + if settings.MEMORY64: + value = f'Number({value})' + receiving.append(f" {assignment} = {value};") else: receiving.append(f" {assignment} = wasmExports['{sym}'];") receiving.append('}') @@ -1010,10 +991,9 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): return '\n'.join(receiving) -def create_module(metadata, function_exports, data_exports, other_exports, library_symbols, aliases): +def create_module(metadata, function_exports, other_exports, library_symbols, aliases): module = [] module.append(create_receiving(function_exports, other_exports, library_symbols, aliases)) - module.append(create_data_exports(data_exports)) sending = create_sending(metadata, library_symbols) if settings.WASM_ESM_INTEGRATION: diff --git a/tools/extract_metadata.py b/tools/extract_metadata.py index a38480c06c828..c39425929578d 100644 --- a/tools/extract_metadata.py +++ b/tools/extract_metadata.py @@ -239,18 +239,6 @@ def get_main_reads_params(module, export_map): return True -def get_data_exports(module, exports): - data_exports = {} - for export in exports: - if export.kind == webassembly.ExternType.GLOBAL: - g = module.get_global(export.index) - # Data symbols (addresses) are exported as immutable Wasm globals. - # mutable globals are handled via get_other_exports - if not g.mutable: - data_exports[export.name] = str(get_global_value(g)) - return data_exports - - def get_function_exports(module): rtn = {} for e in module.get_exports(): @@ -262,14 +250,10 @@ def get_function_exports(module): def get_other_exports(module): rtn = [] for e in module.get_exports(): - if e.kind == webassembly.ExternType.FUNC: - continue if e.kind == webassembly.ExternType.GLOBAL: - g = module.get_global(e.index) - # Immutable globals are handled specially. See get_data_exports - if not g.mutable: - continue - rtn.append(e.name) + rtn.append((e, module.get_global(e.index))) + elif e.kind != webassembly.ExternType.FUNC: + rtn.append((e, None)) return rtn @@ -319,9 +303,8 @@ class Metadata: features: List[str] invoke_funcs: List[str] main_reads_params: bool - data_exports: Dict[str, str] function_exports: Dict[str, webassembly.FuncType] - other_exports: List[str] + other_exports: List[webassembly.Export] all_exports: List[str] @@ -356,7 +339,6 @@ def extract_metadata(filename): metadata.em_js_funcs = em_js_funcs metadata.features = features metadata.main_reads_params = get_main_reads_params(module, export_map) - metadata.data_exports = get_data_exports(module, exports) read_module_imports(module, metadata)