From 4da14b3855bd4d28b559c17fdefd0e440c546c60 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 Sep 2025 21:33:13 -0700 Subject: [PATCH] Support JS symbols that are aliases of native ones We can then use this mechanism to replace the hacky way to we map things like `memory` -> `wasmMemory` and `__indirect_function_table` => `wasmTable`. --- src/jsifier.mjs | 53 +++++++++++------- src/lib/libbootstrap.js | 2 + src/lib/libcore.js | 13 +++-- src/lib/liblegacy.js | 4 +- src/modules.mjs | 12 ++-- src/parseTools.mjs | 14 +++++ src/runtime_common.js | 6 ++ src/runtime_init_memory.js | 2 - src/settings_internal.js | 2 + .../test_codesize_file_preload.expected.js | 6 +- test/codesize/test_codesize_hello_dylink.json | 4 +- .../test_codesize_minimal_O0.expected.js | 11 ++-- .../test_codesize_minimal_pthreads.json | 8 +-- ...t_codesize_minimal_pthreads_memgrowth.json | 4 +- test/codesize/test_unoptimized_code_size.json | 16 +++--- test/other/test_symbol_map.O3.symbols | 4 +- test/test_other.py | 56 +++++++++++++++++++ tools/building.py | 3 +- tools/emscripten.py | 38 ++++++++----- tools/link.py | 2 + tools/shared.py | 5 -- 21 files changed, 185 insertions(+), 80 deletions(-) diff --git a/src/jsifier.mjs b/src/jsifier.mjs index 5342ffa500039..b30a4f8d71b5f 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -40,7 +40,7 @@ import { warningOccured, localFile, } from './utility.mjs'; -import {LibraryManager, librarySymbols} from './modules.mjs'; +import {LibraryManager, librarySymbols, nativeAliases} from './modules.mjs'; const addedLibraryItems = {}; @@ -128,9 +128,13 @@ function isDefined(symName) { } function resolveAlias(symbol) { - var value = LibraryManager.library[symbol]; - if (typeof value == 'string' && value[0] != '=' && LibraryManager.library.hasOwnProperty(value)) { - return value; + while (true) { + var value = LibraryManager.library[symbol]; + if (typeof value == 'string' && value[0] != '=' && (LibraryManager.library.hasOwnProperty(value) || WASM_EXPORTS.has(value))) { + symbol = value; + } else { + break; + } } return symbol; } @@ -639,6 +643,7 @@ function(${args}) { }); let isFunction = false; + let isNativeAlias = false; const postsetId = symbol + '__postset'; const postset = LibraryManager.library[postsetId]; @@ -654,13 +659,22 @@ function(${args}) { if (typeof snippet == 'string') { if (snippet[0] != '=') { - if (LibraryManager.library[snippet]) { + if (LibraryManager.library[snippet] || WASM_EXPORTS.has(snippet)) { // Redirection for aliases. We include the parent, and at runtime // make ourselves equal to it. This avoid having duplicate // functions with identical content. - const aliasTarget = snippet; - snippet = mangleCSymbolName(aliasTarget); - deps.push(aliasTarget); + const aliasTarget = resolveAlias(snippet); + if (WASM_EXPORTS.has(aliasTarget)) { + //printErr(`native alias: ${mangled} -> ${snippet}`); + //console.error(WASM_EXPORTS); + nativeAliases[mangled] = aliasTarget; + snippet = undefined; + isNativeAlias = true; + } else { + //printErr(`js alias: ${mangled} -> ${snippet}`); + deps.push(aliasTarget); + snippet = mangleCSymbolName(aliasTarget); + } } } } else if (typeof snippet == 'object') { @@ -728,15 +742,11 @@ function(${args}) { contentText += ';'; } } else if (typeof snippet == 'undefined') { - // wasmTable is kind of special. In the normal configuration we export - // it from the wasm module under the name `__indirect_function_table` - // but we declare it as an 'undefined' in `libcore.js`. - // Since the normal export mechanism will declare this variable we don't - // want the JS library version of this symbol be declared (otherwise - // it would be a duplicate decl). - // TODO(sbc): This is kind of hacky, we should come up with a better solution. - var isDirectWasmExport = mangled == 'wasmTable'; - if (isDirectWasmExport) { + // For JS library functions that are simply aliases of native symbols, + // we don't need to generate anything here. Instead these get included + // and exported alongside native symbols. + // See `create_receiving` in `tools/emscripten.py`. + if (isNativeAlias) { contentText = ''; } else { contentText = `var ${mangled};`; @@ -752,7 +762,7 @@ function(${args}) { contentText = `var ${mangled} = ${snippet};`; } - if (MODULARIZE == 'instance' && (EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { + if (contentText && MODULARIZE == 'instance' && (EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { // In MODULARIZE=instance mode mark JS library symbols are exported at // the point of declaration. contentText = 'export ' + contentText; @@ -775,11 +785,11 @@ function(${args}) { } } - let commentText = ''; - let docs = LibraryManager.library[symbol + '__docs']; // Add the docs if they exist and if we are actually emitting a declaration. // See the TODO about wasmTable above. - if (docs && contentText != '') { + let docs = LibraryManager.library[symbol + '__docs']; + let commentText = ''; + if (contentText != '' && docs) { commentText += docs + '\n'; } @@ -886,6 +896,7 @@ var proxiedFunctionTable = [ '//FORWARDED_DATA:' + JSON.stringify({ librarySymbols, + nativeAliases, warnings: warningOccured(), asyncFuncs, libraryDefinitions: LibraryManager.libraryDefinitions, diff --git a/src/lib/libbootstrap.js b/src/lib/libbootstrap.js index 16eb2e4dc8ff7..d521315b1cd0c 100644 --- a/src/lib/libbootstrap.js +++ b/src/lib/libbootstrap.js @@ -15,6 +15,8 @@ assert(Object.keys(LibraryManager.library).length === 0); addToLibrary({ $callRuntimeCallbacks: () => {}, + $wasmMemory: 'memory', + $ExitStatus: class { name = 'ExitStatus'; constructor(status) { diff --git a/src/lib/libcore.js b/src/lib/libcore.js index c70228067972a..80b3d89c3e056 100644 --- a/src/lib/libcore.js +++ b/src/lib/libcore.js @@ -1641,7 +1641,7 @@ addToLibrary({ #endif } } - + exportAliases(wasmExports); }, #endif @@ -2150,8 +2150,6 @@ addToLibrary({ #endif // MINIMAL_RUNTIME $asmjsMangle: (x) => { - if (x == 'memory') return 'wasmMemory'; - if (x == '__indirect_function_table') return 'wasmTable'; if (x == '__main_argc_argv') { x = 'main'; } @@ -2287,7 +2285,14 @@ addToLibrary({ }); `, #else - $wasmTable: undefined, + $wasmTable: '__indirect_function_table', +#endif + +#if IMPORTED_MEMORY + // This gets defined in src/runtime_init_memory.js + $wasmMemory: undefined, +#else + $wasmMemory: 'memory', #endif $getUniqueRunDependency: (id) => { diff --git a/src/lib/liblegacy.js b/src/lib/liblegacy.js index 77b2ef52fe124..4b25937628736 100644 --- a/src/lib/liblegacy.js +++ b/src/lib/liblegacy.js @@ -114,8 +114,8 @@ legacyFuncs = { }, // Legacy names for runtime `out`/`err` symbols. - $print: 'out', - $printErr: 'err', + $print: '=out', + $printErr: '=err', // Converts a JS string to an integer base-10. Despite _s, which // suggests signaling error handling, this returns NaN on error. diff --git a/src/modules.mjs b/src/modules.mjs index 96bd8a9e3e375..1aa031dcecfb4 100644 --- a/src/modules.mjs +++ b/src/modules.mjs @@ -29,6 +29,9 @@ import {preprocess, processMacros} from './parseTools.mjs'; // List of symbols that were added from the library. export const librarySymbols = []; +// Map of library symbols which are aliases for native symbols +// e.g. `wasmTable` -> `__indirect_function_table` +export const nativeAliases = {}; const srcDir = fileURLToPath(new URL('.', import.meta.url)); const systemLibdir = path.join(srcDir, 'lib'); @@ -448,7 +451,6 @@ function exportRuntimeSymbols() { 'err', 'callMain', 'abort', - 'wasmMemory', 'wasmExports', 'HEAPF32', 'HEAPF64', @@ -562,13 +564,7 @@ function exportLibrarySymbols() { assert(MODULARIZE != 'instance'); const results = ['// Begin JS library exports']; for (const ident of librarySymbols) { - if (EXPORT_ALL || EXPORTED_FUNCTIONS.has(ident)) { - // Special case for wasmTable which can be both a JS library symbol but - // also a wasm export. See isDirectWasmExport in jsifier.mjs. - // FIXME: Remove this hack - if (ident == 'wasmTable' && WASM_EXPORTS.has('__indirect_function_table')) { - continue; - } + if ((EXPORT_ALL || EXPORTED_FUNCTIONS.has(ident)) && !nativeAliases[ident]) { results.push(exportSymbol(ident)); } } diff --git a/src/parseTools.mjs b/src/parseTools.mjs index 1c88461836ee0..6c9fb61215f93 100644 --- a/src/parseTools.mjs +++ b/src/parseTools.mjs @@ -24,6 +24,8 @@ import { srcDir, } from './utility.mjs'; +import { nativeAliases } from './modules.mjs'; + const FOUR_GB = 4 * 1024 * 1024 * 1024; const WASM_PAGE_SIZE = 64 * 1024; const FLOAT_TYPES = new Set(['float', 'double']); @@ -1155,6 +1157,17 @@ function nodeWWDetection() { } } +function makeExportAliases() { + var res = '' + for (var [alias, ex] of Object.entries(nativeAliases)) { + if (ASSERTIONS) { + res += ` assert(wasmExports['${ex}'], 'alias target "${ex}" not found in wasmExports');\n`; + } + res += ` globalThis['${alias}'] = wasmExports['${ex}'];\n`; + } + return res; +} + addToCompileTimeContext({ ATEXITS, ATPRERUNS, @@ -1204,6 +1217,7 @@ addToCompileTimeContext({ isSymbolNeeded, makeDynCall, makeEval, + makeExportAliases, makeGetValue, makeHEAPView, makeModuleReceive, diff --git a/src/runtime_common.js b/src/runtime_common.js index ed9c695f7c14b..6110d611ab6e8 100644 --- a/src/runtime_common.js +++ b/src/runtime_common.js @@ -174,3 +174,9 @@ if (ENVIRONMENT_IS_NODE) { #endif // !IMPORTED_MEMORY && ASSERTIONS #include "memoryprofiler.js" + +#if !DECLARE_ASM_MODULE_EXPORTS +function exportAliases(wasmExports) { +{{{ makeExportAliases() }}} +} +#endif diff --git a/src/runtime_init_memory.js b/src/runtime_init_memory.js index 9e522f5f05e8e..561dfb3adfc26 100644 --- a/src/runtime_init_memory.js +++ b/src/runtime_init_memory.js @@ -9,8 +9,6 @@ #error "this file should not be be included when IMPORTED_MEMORY is set" #endif -var wasmMemory; - // check for full engine support (use string 'subarray' to avoid closure compiler confusion) function initMemory() { diff --git a/src/settings_internal.js b/src/settings_internal.js index 24581016c317c..78d2d797d7a63 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -275,3 +275,5 @@ var OUTPUT_FORMAT = ''; // Whether we should load the WASM source map at runtime. // This is enabled automatically when using -gsource-map with sanitizers. var LOAD_SOURCE_MAP = false; + +var ALIASES = []; diff --git a/test/codesize/test_codesize_file_preload.expected.js b/test/codesize/test_codesize_file_preload.expected.js index 649f009a77059..6a54d91bcc8e2 100644 --- a/test/codesize/test_codesize_file_preload.expected.js +++ b/test/codesize/test_codesize_file_preload.expected.js @@ -3154,12 +3154,12 @@ Module["FS_createLazyFile"] = FS_createLazyFile; // End JS library exports // end include: postlibrary.js // Imports from the Wasm binary. -var _main, wasmMemory, wasmTable; +var _main, memory, __indirect_function_table, wasmMemory; function assignWasmExports(wasmExports) { _main = Module["_main"] = wasmExports["d"]; - wasmMemory = wasmExports["b"]; - wasmTable = wasmExports["__indirect_function_table"]; + memory = wasmMemory = wasmExports["b"]; + __indirect_function_table = wasmExports["__indirect_function_table"]; } var wasmImports = { diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index 67d37ec2376cf..72b36bbfdb613 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -1,10 +1,10 @@ { "a.out.js": 26931, - "a.out.js.gz": 11473, + "a.out.js.gz": 11472, "a.out.nodebug.wasm": 18567, "a.out.nodebug.wasm.gz": 9199, "total": 45498, - "total_gz": 20672, + "total_gz": 20671, "sent": [ "__heap_base", "__indirect_function_table", diff --git a/test/codesize/test_codesize_minimal_O0.expected.js b/test/codesize/test_codesize_minimal_O0.expected.js index c818094d9d9e2..44c3d41367a32 100644 --- a/test/codesize/test_codesize_minimal_O0.expected.js +++ b/test/codesize/test_codesize_minimal_O0.expected.js @@ -850,6 +850,8 @@ async function createWasm() { err(text); } }; + + // End JS library code // include: postlibrary.js @@ -1056,7 +1058,6 @@ missingLibrarySymbols.forEach(missingLibrarySymbol) 'err', 'callMain', 'abort', - 'wasmMemory', 'wasmExports', 'HEAPF32', 'HEAPF64', @@ -1084,6 +1085,7 @@ missingLibrarySymbols.forEach(missingLibrarySymbol) 'warnOnce', 'readEmAsmArgsArray', 'wasmTable', + 'wasmMemory', 'noExitRuntime', 'addRunDependency', 'removeRunDependency', @@ -1315,8 +1317,9 @@ var _emscripten_stack_get_end = makeInvalidEarlyAccess('_emscripten_stack_get_en var __emscripten_stack_restore = makeInvalidEarlyAccess('__emscripten_stack_restore'); var __emscripten_stack_alloc = makeInvalidEarlyAccess('__emscripten_stack_alloc'); var _emscripten_stack_get_current = makeInvalidEarlyAccess('_emscripten_stack_get_current'); +var memory = makeInvalidEarlyAccess('memory'); +var __indirect_function_table = makeInvalidEarlyAccess('__indirect_function_table'); var wasmMemory = makeInvalidEarlyAccess('wasmMemory'); -var wasmTable = makeInvalidEarlyAccess('wasmTable'); function assignWasmExports(wasmExports) { _add = Module['_add'] = createExportWrapper('add', 2); @@ -1328,8 +1331,8 @@ function assignWasmExports(wasmExports) { __emscripten_stack_restore = wasmExports['_emscripten_stack_restore']; __emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc']; _emscripten_stack_get_current = wasmExports['emscripten_stack_get_current']; - wasmMemory = wasmExports['memory']; - wasmTable = wasmExports['__indirect_function_table']; + memory = wasmMemory = wasmExports['memory']; + __indirect_function_table = wasmExports['__indirect_function_table']; } var _global_val = Module['_global_val'] = 65536; diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index f11361b09e81a..ea2b2571aa3f8 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -1,10 +1,10 @@ { - "a.out.js": 7613, - "a.out.js.gz": 3764, + "a.out.js": 7609, + "a.out.js.gz": 3762, "a.out.nodebug.wasm": 19599, "a.out.nodebug.wasm.gz": 9063, - "total": 27212, - "total_gz": 12827, + "total": 27208, + "total_gz": 12825, "sent": [ "a (memory)", "b (emscripten_get_now)", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index d6360abab8733..03cff647dc2a3 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -1,9 +1,9 @@ { - "a.out.js": 8040, + "a.out.js": 8036, "a.out.js.gz": 3962, "a.out.nodebug.wasm": 19600, "a.out.nodebug.wasm.gz": 9064, - "total": 27640, + "total": 27636, "total_gz": 13026, "sent": [ "a (memory)", diff --git a/test/codesize/test_unoptimized_code_size.json b/test/codesize/test_unoptimized_code_size.json index 16940da00e92d..621eb4ed27b84 100644 --- a/test/codesize/test_unoptimized_code_size.json +++ b/test/codesize/test_unoptimized_code_size.json @@ -1,16 +1,16 @@ { - "hello_world.js": 55400, - "hello_world.js.gz": 17483, + "hello_world.js": 55508, + "hello_world.js.gz": 17498, "hello_world.wasm": 15127, "hello_world.wasm.gz": 7450, - "no_asserts.js": 26559, - "no_asserts.js.gz": 8867, + "no_asserts.js": 26614, + "no_asserts.js.gz": 8877, "no_asserts.wasm": 12227, "no_asserts.wasm.gz": 6010, - "strict.js": 53438, - "strict.js.gz": 16822, + "strict.js": 53546, + "strict.js.gz": 16835, "strict.wasm": 15127, "strict.wasm.gz": 7447, - "total": 177878, - "total_gz": 64079 + "total": 178149, + "total_gz": 64117 } diff --git a/test/other/test_symbol_map.O3.symbols b/test/other/test_symbol_map.O3.symbols index 4bf0271be9878..54a7bd0c046d5 100644 --- a/test/other/test_symbol_map.O3.symbols +++ b/test/other/test_symbol_map.O3.symbols @@ -3,4 +3,6 @@ 2:middle 3:main 4:foo::cpp_func(int) -5:__wasm_call_ctors +5:emscripten_stack_get_current +6:_emscripten_stack_restore +7:__wasm_call_ctors diff --git a/test/test_other.py b/test/test_other.py index b0db22cb9946e..8e01ea79763ce 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -4888,6 +4888,62 @@ def test_jslib_include(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js']) self.assertContained('foo.js:5: file not found: inc.js', err) + @parameterized({ + '': ([],), + 'closure': (['--closure=1'],), + }) + def test_jslib_aliases(self, args): + create_file('foo.js', ''' + addToLibrary({ + foo: () => 42, + foo_alias: 'foo', + + // Normal JS function that calls a native function + call_native__deps: ['native_func'], + call_native: () => _native_func(), + + // JS function that calls nativeAlias + call_native_alias__deps: ['$nativeAlias'], + call_native_alias: () => nativeAlias(), + + // This is a JS-only symbol (i.e. no leading underscore) that + // aliases a native symbol. + $nativeAlias__deps: ['native_func2'], + $nativeAlias: 'native_func2', + }); + ''') + create_file('main.c', r''' + #include + #include + int foo(); + int foo_alias(); + int call_native(); + int call_native_alias(); + + int native_func() { + return 43; + } + + int native_func2() { + return 44; + } + + int main() { + printf("foo: %d\n", foo()); + printf("foo_alias: %d\n", foo_alias()); + printf("call_native: %d\n", call_native()); + printf("call_native_alias: %d\n", call_native_alias()); + return 0; + } + ''') + expected = '''\ +foo: 42 +foo_alias: 42 +call_native: 43 +call_native_alias: 44 +''' + self.do_runf('main.c', expected, cflags=['--js-library', 'foo.js'] + args) + def test_postjs_errors(self): create_file('post.js', '#preprocess\n#error This is an error') err = self.expect_fail([EMCC, test_file('hello_world.c'), '--post-js', 'post.js']) diff --git a/tools/building.py b/tools/building.py index 58c3756923241..3c95993c84c56 100644 --- a/tools/building.py +++ b/tools/building.py @@ -571,7 +571,8 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None): # externs file for the exports, Closure is able to reason about the 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_EXPORTS]) + exports = [asmjs_mangle(i) for i in settings.WASM_EXPORTS] + settings.ALIASES + module_exports_suppressions = '\n'.join(['/**\n * @suppress {duplicate, undefinedVars}\n */\nvar %s;\n' % e for e in exports]) exports_file = shared.get_temp_files().get('.js', prefix='emcc_module_exports_') exports_file.write(module_exports_suppressions.encode()) exports_file.close() diff --git a/tools/emscripten.py b/tools/emscripten.py index 793b40620ee61..e37e6e1f86bb7 100644 --- a/tools/emscripten.py +++ b/tools/emscripten.py @@ -421,8 +421,10 @@ 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, global_exports, other_exports, forwarded_json['librarySymbols']) + parts += create_module(metadata, function_exports, global_exports, other_exports, + forwarded_json['librarySymbols'], forwarded_json['nativeAliases']) parts.append(post) + settings.ALIASES = list(forwarded_json['nativeAliases'].keys()) full_js_module = ''.join(parts) full_js_module = apply_static_code_hooks(forwarded_json, full_js_module) @@ -906,7 +908,7 @@ def should_export(sym): return settings.EXPORT_ALL or (settings.EXPORT_KEEPALIVE and sym in settings.EXPORTED_FUNCTIONS) -def create_receiving(function_exports, other_exports, library_symbols): +def create_receiving(function_exports, other_exports, library_symbols, aliases): generate_dyncall_assignment = 'dynCalls' in library_symbols receiving = ['\n// Imports from the Wasm binary.'] @@ -919,6 +921,9 @@ def create_receiving(function_exports, other_exports, library_symbols): exports.append(f'{sym} as {mangled}') else: exports.append(sym) + for alias, target in aliases.items(): + exports.append(f'{target} as {alias}') + receiving.append('import {') receiving.append(' ' + ',\n '.join(exports)) receiving.append(f"}} from './{settings.WASM_BINARY_FILE}';") @@ -948,29 +953,33 @@ def create_receiving(function_exports, other_exports, library_symbols): for name in other_exports: exports[name] = None + mangled = [asmjs_mangle(s) for s in exports] + list(aliases.keys()) if settings.ASSERTIONS: # In debug builds we generate trapping functions in case # folks try to call/use a reference that was taken before the # wasm module is available. - for sym in exports: - mangled = asmjs_mangle(sym) - assignment = mangled - if (settings.MODULARIZE or not settings.MINIMAL_RUNTIME) and should_export(mangled) and settings.MODULARIZE != 'instance': - assignment += f" = Module['{mangled}']" - receiving.append(f"var {assignment} = makeInvalidEarlyAccess('{mangled}');") + for sym in mangled: + assignment = sym + if (settings.MODULARIZE or not settings.MINIMAL_RUNTIME) and should_export(sym) and settings.MODULARIZE != 'instance': + assignment += f" = Module['{sym}']" + receiving.append(f"var {assignment} = makeInvalidEarlyAccess('{sym}');") else: # Declare all exports in a single var statement sep = ',\n ' - mangled = [asmjs_mangle(s) for s in exports] receiving.append(f'var {sep.join(mangled)};\n') if settings.MODULARIZE == 'instance': - mangled = [asmjs_mangle(e) for e in exports] esm_exports = [e for e in mangled if should_export(e)] if esm_exports: esm_exports = ', '.join(esm_exports) receiving.append(f'export {{ {esm_exports} }};') + alias_inverse_map = {} + logger.debug(json.dumps(aliases)) + for sym, alias in aliases.items(): + assert alias in exports, f'expected alias target ({alias}) to be exported' + alias_inverse_map.setdefault(alias, []).append(sym) + receiving.append('\nfunction assignWasmExports(wasmExports) {') for sym, sig in exports.items(): is_function = sig is not None @@ -980,7 +989,10 @@ def create_receiving(function_exports, other_exports, library_symbols): sig_str = sym.replace('dynCall_', '') assignment += f" = dynCalls['{sig_str}']" if (settings.MODULARIZE or not settings.MINIMAL_RUNTIME) and should_export(mangled) and settings.MODULARIZE != 'instance': - assignment += f" = Module['{mangled}']" + assignment += f" = Module['{mangled}']" + if sym in alias_inverse_map: + for target in alias_inverse_map[sym]: + assignment += f" = {target}" if is_function and install_debug_wrapper(sym): nargs = len(sig.params) receiving.append(f" {assignment} = createExportWrapper('{sym}', {nargs});") @@ -991,9 +1003,9 @@ def create_receiving(function_exports, other_exports, library_symbols): return '\n'.join(receiving) -def create_module(metadata, function_exports, global_exports, other_exports, library_symbols): +def create_module(metadata, function_exports, global_exports, other_exports, library_symbols, aliases): module = [] - module.append(create_receiving(function_exports, other_exports, library_symbols)) + module.append(create_receiving(function_exports, other_exports, library_symbols, aliases)) module.append(create_global_exports(global_exports)) sending = create_sending(metadata, library_symbols) diff --git a/tools/link.py b/tools/link.py index e13cf39d11778..a8a55d5d61afd 100644 --- a/tools/link.py +++ b/tools/link.py @@ -1069,6 +1069,8 @@ def limit_incoming_module_api(): if prop not in settings.ALL_INCOMING_MODULE_JS_API: diagnostics.warning('unused-command-line-argument', f'invalid entry in INCOMING_MODULE_JS_API: {prop}') + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$wasmMemory') + if 'noExitRuntime' in settings.INCOMING_MODULE_JS_API: settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$noExitRuntime') diff --git a/tools/shared.py b/tools/shared.py index 7585afe252069..4ab4b361f2a6d 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -637,11 +637,6 @@ def asmjs_mangle(name): Prepends '_' and replaces non-alphanumerics with '_'. Used by wasm backend for JS library consistency with asm.js. """ - # We rename certain well-known exports to match what we call them in JS - if name == 'memory': - return 'wasmMemory' - if name == '__indirect_function_table': - return 'wasmTable' # We also use this function to convert the clang-mangled `__main_argc_argv` # to simply `main` which is expected by the emscripten JS glue code. if name == '__main_argc_argv':