Skip to content

Commit 696c7ed

Browse files
authored
Generate wrappers for JS aliases when needed (#25918)
In many cases we cannot alias the same function if we have a different signature. The two main examples are: 1. Dynamic linking where each function needs its own `.sig` attribute. 2. wasm64 / bigint handling where each function might have different signature conversion rules applied. Fixes #25256
1 parent 9a35a61 commit 696c7ed

File tree

4 files changed

+50
-12
lines changed

4 files changed

+50
-12
lines changed

src/jsifier.mjs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,14 @@ function addImplicitDeps(snippet, deps) {
255255
}
256256
}
257257

258+
function sigToArgs(sig) {
259+
const args = []
260+
for (var i = 1; i < sig.length; i++) {
261+
args.push(`a${i}`);
262+
}
263+
return args.join(',')
264+
}
265+
258266
function handleI64Signatures(symbol, snippet, sig, i53abi) {
259267
// Handle i64 parameters and return values.
260268
//
@@ -623,7 +631,7 @@ function(${args}) {
623631
}
624632
}
625633

626-
const isFunction = typeof snippet == 'function';
634+
let isFunction = typeof snippet == 'function';
627635
let isNativeAlias = false;
628636

629637
const postsetId = symbol + '__postset';
@@ -642,20 +650,34 @@ function(${args}) {
642650
// Redirection for aliases. We include the parent, and at runtime
643651
// make ourselves equal to it. This avoid having duplicate
644652
// functions with identical content.
645-
if (WASM_EXPORTS.has(snippet)) {
646-
//printErr(`native alias: ${mangled} -> ${snippet}`);
647-
//console.error(WASM_EXPORTS);
648-
nativeAliases[mangled] = snippet;
653+
const aliasTarget = snippet;
654+
if (WASM_EXPORTS.has(aliasTarget)) {
655+
debugLog(`native alias: ${mangled} -> ${aliasTarget}`);
656+
nativeAliases[mangled] = aliasTarget;
649657
snippet = undefined;
650658
isNativeAlias = true;
651659
} else {
652-
//printErr(`js alias: ${mangled} -> ${snippet}`);
653-
snippet = mangleCSymbolName(snippet);
660+
debugLog(`js alias: ${mangled} -> ${aliasTarget}`);
661+
snippet = mangleCSymbolName(aliasTarget);
662+
// When we have an alias for another JS function we can normally
663+
// point them at the same function. However, in some cases (where
664+
// signatures are relevant and they differ between and alais and
665+
// it's target) we need to construct a forwarding function from
666+
// one to the other.
667+
const isSigRelevant = MAIN_MODULE || RELOCATABLE || MEMORY64 || CAN_ADDRESS_2GB || (sig && sig.includes('j'));
668+
const targetSig = LibraryManager.library[aliasTarget + '__sig'];
669+
if (isSigRelevant && sig && targetSig && sig != targetSig) {
670+
debugLog(`${symbol}: Alias target (${aliasTarget}) has different signature (${sig} vs ${targetSig})`)
671+
isFunction = true;
672+
snippet = `(${sigToArgs(sig)}) => ${snippet}(${sigToArgs(targetSig)})`;
673+
}
654674
}
655675
} else if (typeof snippet == 'object') {
656676
snippet = stringifyWithFunctions(snippet);
657677
addImplicitDeps(snippet, deps);
658-
} else if (isFunction) {
678+
}
679+
680+
if (isFunction) {
659681
snippet = processLibraryFunction(snippet, symbol, mangled, deps, isStub);
660682
addImplicitDeps(snippet, deps);
661683
if (CHECK_DEPS && !isUserSymbol) {

src/lib/libemval.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,7 @@ ${functionBody}
351351
352352
// Same as `_emval_invoke`, just imported into Wasm under a different return type.
353353
// TODO: remove this if/when https://github.com/emscripten-core/emscripten/issues/20478 is fixed.
354-
_emval_invoke_i64__deps: ['_emval_invoke'],
355-
_emval_invoke_i64: '=__emval_invoke',
354+
_emval_invoke_i64: '_emval_invoke',
356355

357356
_emval_typeof__deps: ['$Emval'],
358357
_emval_typeof: (handle) => {

test/codesize/test_codesize_hello_dylink_all.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"a.out.js": 245661,
2+
"a.out.js": 245751,
33
"a.out.nodebug.wasm": 573748,
4-
"total": 819409,
4+
"total": 819499,
55
"sent": [
66
"IMG_Init",
77
"IMG_Load",

test/test_jslib.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ def test_jslib_include(self):
495495
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js'])
496496
self.assertContained('foo.js:5: file not found: inc.js', err)
497497

498+
@also_with_wasm64
499+
@also_without_bigint
498500
@parameterized({
499501
'': ([],),
500502
'closure': (['--closure=1'],),
@@ -503,8 +505,17 @@ def test_jslib_aliases(self, args):
503505
create_file('foo.js', '''
504506
addToLibrary({
505507
foo: () => 42,
508+
foo__sig: 'i',
509+
506510
foo_alias: 'foo',
507511
512+
foo_alias_i64: 'foo',
513+
foo_alias_i64__sig: 'j',
514+
foo_alias_i64__i53abi: true,
515+
516+
foo_alias_ptr: 'foo',
517+
foo_alias_ptr__sig: 'p',
518+
508519
// Normal JS function that calls a native function
509520
call_native__deps: ['native_func'],
510521
call_native: () => _native_func(),
@@ -524,6 +535,8 @@ def test_jslib_aliases(self, args):
524535
#include <emscripten.h>
525536
int foo();
526537
int foo_alias();
538+
void* foo_alias_ptr();
539+
int64_t foo_alias_i64();
527540
int call_native();
528541
int call_native_alias();
529542
@@ -538,6 +551,8 @@ def test_jslib_aliases(self, args):
538551
int main() {
539552
printf("foo: %d\n", foo());
540553
printf("foo_alias: %d\n", foo_alias());
554+
printf("foo_alias_i64: %lld\n", foo_alias_i64());
555+
printf("foo_alias_ptr: %p\n", foo_alias_ptr());
541556
printf("call_native: %d\n", call_native());
542557
printf("call_native_alias: %d\n", call_native_alias());
543558
return 0;
@@ -546,6 +561,8 @@ def test_jslib_aliases(self, args):
546561
expected = '''\
547562
foo: 42
548563
foo_alias: 42
564+
foo_alias_i64: 42
565+
foo_alias_ptr: 0x2a
549566
call_native: 43
550567
call_native_alias: 44
551568
'''

0 commit comments

Comments
 (0)