Skip to content

Commit f9059f1

Browse files
committed
Update API and tests.
1 parent df01a0d commit f9059f1

8 files changed

+87
-22
lines changed

emcc.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,8 @@ def default_setting(name, new_default):
12831283
exit_with_error('Invalid option -s CLOSURE_WARNINGS=%s specified! Allowed values are "quiet", "warn" or "error".' % shared.Settings.CLOSURE_WARNINGS)
12841284

12851285
# Calling function pointers from JS libraries is default runtime functionality, so always include the functionality. (to be DCEd if not used)
1286-
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$dynCall']
1286+
if shared.Settings.WASM_DYNCALLS:
1287+
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$dynCall']
12871288

12881289
if shared.Settings.MAIN_MODULE:
12891290
assert not shared.Settings.SIDE_MODULE
@@ -1710,7 +1711,7 @@ def check_memory_setting(setting):
17101711
if shared.Settings.USE_PTHREADS or shared.Settings.RELOCATABLE or shared.Settings.ASYNCIFY_LAZY_LOAD_CODE or shared.Settings.WASM2JS:
17111712
shared.Settings.IMPORTED_MEMORY = 1
17121713

1713-
if shared.Settings.WASM_BIGINT:
1714+
if shared.Settings.WASM_BIGINT and not shared.Settings.WASM_DYNCALLS:
17141715
shared.Settings.LEGALIZE_JS_FFI = 0
17151716

17161717
shared.Settings.GENERATE_SOURCE_MAP = shared.Settings.DEBUG_LEVEL >= 4 and not shared.Settings.SINGLE_FILE

emscripten.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def compute_minimal_runtime_initializer_and_exports(post, exports, receiving):
6464

6565
static_dyncall_sig_functions = ''
6666

67-
if shared.Settings.USE_LEGACY_DYNCALLS or not shared.Settings.WASM_BIGINT:
67+
if shared.Settings.WASM_DYNCALLS:
6868
if len([x for x in exports_that_are_not_initializers if x.startswith('dynCall_')]) > 0:
6969
exports_that_are_not_initializers += ['dynCalls = {}']
7070
else:
@@ -75,7 +75,8 @@ def compute_minimal_runtime_initializer_and_exports(post, exports, receiving):
7575
exports_that_are_not_initializers = [x for x in exports_that_are_not_initializers if not x.startswith('dynCall_')]
7676

7777
post = post.replace('/*** ASM_MODULE_EXPORTS_DECLARES ***/', 'var ' + ',\n '.join(exports_that_are_not_initializers) + ';')
78-
post = post.replace('/*** STATIC_DYNCALL_SIG_FUNCTIONS ***/', static_dyncall_sig_functions)
78+
# TODO: Check codegen again
79+
# post = post.replace('/*** STATIC_DYNCALL_SIG_FUNCTIONS ***/', static_dyncall_sig_functions)
7980

8081
# Generate assignments from all asm.js/wasm exports out to the JS variables above: e.g. a = asm['a']; b = asm['b'];
8182
post = post.replace('/*** ASM_MODULE_EXPORTS ***/', receiving)
@@ -430,7 +431,7 @@ def finalize_wasm(infile, outfile, memfile, DEBUG):
430431
# (which matches what llvm+lld has given us)
431432
if shared.Settings.DEBUG_LEVEL >= 2 or shared.Settings.ASYNCIFY_ADD or shared.Settings.ASYNCIFY_ADVISE or shared.Settings.ASYNCIFY_ONLY or shared.Settings.ASYNCIFY_REMOVE or shared.Settings.EMIT_SYMBOL_MAP or shared.Settings.PROFILING_FUNCS:
432433
args.append('-g')
433-
if shared.Settings.WASM_BIGINT:
434+
if shared.Settings.WASM_BIGINT and not shared.Settings.WASM_DYNCALLS: # TODO: This may be troublematic?
434435
args.append('--bigint')
435436
if True:##shared.Settings.USE_LEGACY_DYNCALLS:
436437
# we need to add all dyncalls to the wasm
@@ -728,7 +729,9 @@ def create_receiving(exports):
728729
return ''
729730

730731
exports_that_are_not_initializers = [x for x in exports if x != WASM_INIT_FUNC]
731-
if not shared.Settings.USE_LEGACY_DYNCALLS and shared.Settings.WASM_BIGINT:
732+
733+
# If we are not building with dynCall() support, filter out all the dynCall_ exports.
734+
if not shared.Settings.WASM_DYNCALLS:
732735
exports_that_are_not_initializers = [x for x in exports_that_are_not_initializers if not x.startswith('dynCall_')]
733736

734737
receiving = []
@@ -745,7 +748,7 @@ def create_receiving(exports):
745748
# _main = asm["_main"];
746749
for s in exports_that_are_not_initializers:
747750
mangled = asmjs_mangle(s)
748-
dynCallAssignment = ('dynCalls["' + s.replace('dynCall_', '') + '"] = ') if shared.Settings.USE_LEGACY_DYNCALLS or not shared.Settings.WASM_BIGINT and mangled.startswith('dynCall_') else ''
751+
dynCallAssignment = ('dynCalls["' + s.replace('dynCall_', '') + '"] = ') if shared.Settings.WASM_DYNCALLS and mangled.startswith('dynCall_') else ''
749752
receiving += [dynCallAssignment + mangled + ' = asm["' + s + '"];']
750753
else:
751754
if shared.Settings.MINIMAL_RUNTIME:

src/library_dyncall.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mergeInto(LibraryManager.library, {
22
{{{ (function() { global.wbind = function() { return SHRINK_LEVEL == 0 ? 'wbind' : 'wasmTable.get'; }; return null; })(); }}}
3-
{{{ (function() { global.getDynCaller = function(sig) { return MINIMAL_RUNTIME ? `dynCalls[${sig}]` : `Module["dynCall_${sig}]`; }; return null; })(); }}}
3+
{{{ (function() { global.getDynCaller = function(sig) { return MINIMAL_RUNTIME ? `dynCalls[${sig}]` : `Module["dynCall_"+${sig}]`; }; return null; })(); }}}
44

55
#if SHRINK_LEVEL == 0
66
// A mirror copy of contents of wasmTable in JS side, to avoid relatively
@@ -17,8 +17,10 @@ mergeInto(LibraryManager.library, {
1717
return func;
1818
},
1919

20+
#if WASM_DYNCALLS
2021
$dynCall__deps: ['$wbind'],
2122
$bindDynCall__deps: ['$wbind'],
23+
#endif
2224
$wbindArray__deps: ['$wbind'],
2325
#else
2426
$wbind: function(funcPtr) {
@@ -37,6 +39,7 @@ mergeInto(LibraryManager.library, {
3739
: function() { return func(); }
3840
},
3941

42+
#if WASM_DYNCALLS
4043
// A helper that returns a function that can be used to invoke function pointers, i.e.
4144
// getDynCaller('vi')(funcPtr, myInt);
4245
$getDynCaller: function(sig, funcPtr) {
@@ -55,13 +58,21 @@ mergeInto(LibraryManager.library, {
5558
: function() { return func(); }
5659
},
5760

61+
#if SHRINK_LEVEL
62+
$dynCall__deps: ['$bindDynCall'],
63+
#endif
5864
$dynCall: function(sig, funcPtr, args) {
65+
#if SHRINK_LEVEL
66+
return bindDynCall(sig, funcPtr)(args);
67+
#else
5968
// For int64 signatures, use the dynCall_sig dispatch mechanism.
6069
if (sig.includes('j')) {
6170
return {{{getDynCaller('sig')}}}.apply(null, [funcPtr].concat(args));
6271
}
6372

6473
// For non-int64 signatures, invoke via the wasm table.
6574
return {{{wbind()}}}(funcPtr).apply(null, args);
66-
}
75+
#endif
76+
},
77+
#endif
6778
});

src/settings.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,10 @@ var BINARYEN_EXTRA_PASSES = "";
11451145
// (This option was formerly called BINARYEN_ASYNC_COMPILATION)
11461146
var WASM_ASYNC_COMPILATION = 1;
11471147

1148+
// If true, enables emitting dynCall() and dynCall_sig() based function pointer
1149+
// invokers to call function pointers from JS to Wasm.
1150+
var WASM_DYNCALLS = 1;
1151+
11481152
// WebAssembly integration with JavaScript BigInt. When enabled we don't need
11491153
// to legalize i64s into pairs of i32s, as the wasm VM will use a BigInt where
11501154
// an i64 is used.
File renamed without changes.

tests/test_dyncalls.js renamed to tests/core/test_dyncalls.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,81 @@
11
mergeInto(LibraryManager.library, {
2-
test_dyncalls_vijdf__deps: ['$getDynCaller', '$bindDynCall', '$wbind', '$wbindArray'],
2+
test_dyncalls_vijdf__deps: [
3+
#if WASM_DYNCALLS
4+
'$getDynCaller', '$bindDynCall',
5+
#endif
6+
'$wbind', '$wbindArray'],
37
test_dyncalls_vijdf: function(funcPtr) {
4-
#if WASM_BIGINT != 2
8+
#if WASM_DYNCALLS
59
// 1. Directly access a function pointer via a static signature (32-bit ABI)
610
// (this is the fastest way to call a function pointer when the signature is statically known in WASM_BIGINT==0 builds)
711
dynCall_vijdf(funcPtr, 1, /*lo=*/2, /*hi=*/3, 4, 5); // Available only in WASM_BIGINT != 2 builds
812

913
// 2. Access a function pointer using the convenience/legacy 'dynCall' function (32-bit ABI)
1014
// (this form should never be used, it is suboptimal for performance, but provided for legacy compatibility)
11-
dynCall('vijdf', funcPtr, [3, /*lo=*/4, /*hi=*/5, 6, 7]); // Available only in WASM_BIGINT != 2 builds
15+
dynCall('vijdf', funcPtr, [2, /*lo=*/3, /*hi=*/4, 5, 6]); // Available only in WASM_BIGINT != 2 builds
1216

1317
// 3. Obtain a dynamic function caller to a given signature and call it with .apply() (32-bit ABI)
1418
// (this form should be used when dealing with a dynamic input signature problem with varying length of function args, and funcPtr + args are fused together in one array)
15-
getDynCaller('vijdf').apply(null, [funcPtr, 4, /*lo=*/5, /*hi=*/6, 7, 8]); // Available only in WASM_BIGINT != 2 builds
19+
getDynCaller('vijdf').apply(null, [funcPtr, 3, /*lo=*/4, /*hi=*/5, 6, 7]); // Available only in WASM_BIGINT != 2 builds
1620

1721
// 4. Obtain a function wrapper to given function pointer and call it by submitting args in an array (32-bit ABI)
1822
// (this form should be used when dealing with a dynamic input signature problem with varying length of function args, but funcPtr and args params are dealt with separately)
1923
bindDynCall('vijdf', funcPtr)([4, /*lo=*/5, /*hi=*/6, 7, 8]); // Available only in WASM_BIGINT != 2 builds
24+
#else
25+
// Appease test runner and output the same text if not building with WASM_DYNCALLS enabled.
26+
wbind(funcPtr)(1, BigInt(2) | (BigInt(3) << BigInt(32)), 4, 5);
27+
wbind(funcPtr)(2, BigInt(3) | (BigInt(4) << BigInt(32)), 5, 6);
28+
wbind(funcPtr)(3, BigInt(4) | (BigInt(5) << BigInt(32)), 6, 7);
29+
wbind(funcPtr)(4, BigInt(5) | (BigInt(6) << BigInt(32)), 7, 8);
2030
#endif
2131

2232
#if WASM_BIGINT
2333
// 5. Directly access a function pointer via a static signature (64-bit ABI)
2434
// (this is the fastest way to call a function pointer when the signature is statically known in WASM_BIGINT>0 builds)
25-
wbind(funcPtr)(2, BigInt(3) | (BigInt(4) << BigInt(32)), 5, 6); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
35+
wbind(funcPtr)(5, BigInt(6) | (BigInt(7) << BigInt(32)), 8, 9); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
2636

2737
// 6. Obtain an array form access to the specified signature. (64-bit ABI)
2838
// (this form should be used when dealing with a dynamic input signature problem with varying length of function args)
29-
wbindArray(funcPtr)([5, BigInt(6) | (BigInt(7) << BigInt(32)), 8, 9]); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
39+
wbindArray(funcPtr)([6, BigInt(7) | (BigInt(8) << BigInt(32)), 9, 10]); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
40+
#else
41+
// Appease test runner and output the same text if not building with WASM_BIGINT enabled.
42+
dynCall_vijdf(funcPtr, 5, /*lo=*/6, /*hi=*/7, 8, 9);
43+
dynCall_vijdf(funcPtr, 6, /*lo=*/7, /*hi=*/8, 9, 10);
3044
#endif
3145
},
3246

3347
test_dyncalls_iii: function(funcPtr) {
34-
#if WASM_BIGINT != 2
48+
#if WASM_DYNCALLS
3549
// 1. Directly access a function pointer via a static signature (32-bit ABI)
3650
// (this is the fastest way to call a function pointer when the signature is statically known in WASM_BIGINT==0 builds)
3751
var ret = dynCall_iii(funcPtr, 1, 2); // Available only in WASM_BIGINT != 2 builds
3852
console.log('iii returned ' + ret);
3953

4054
// 2. Access a function pointer using the convenience/legacy 'dynCall' function (32-bit ABI)
4155
// (this form should never be used, it is suboptimal for performance, but provided for legacy compatibility)
42-
var ret = dynCall('iii', funcPtr, [3, 4]); // Available only in WASM_BIGINT != 2 builds
56+
var ret = dynCall('iii', funcPtr, [2, 3]); // Available only in WASM_BIGINT != 2 builds
4357
console.log('iii returned ' + ret);
4458

4559
// 3. Obtain a dynamic function caller to a given signature and call it with .apply() (32-bit ABI)
4660
// (this form should be used when dealing with a dynamic input signature problem with varying length of function args, and funcPtr + args are fused together in one array)
47-
var ret = getDynCaller('iii').apply(null, [funcPtr, 4, 5]); // Available only in WASM_BIGINT != 2 builds
61+
var ret = getDynCaller('iii').apply(null, [funcPtr, 3, 4]); // Available only in WASM_BIGINT != 2 builds
4862
console.log('iii returned ' + ret);
4963

5064
// 4. Obtain a function wrapper to given function pointer and call it by submitting args in an array (32-bit ABI)
5165
// (this form should be used when dealing with a dynamic input signature problem with varying length of function args, but funcPtr and args params are dealt with separately)
52-
var ret = bindDynCall('iii', funcPtr)([5, 6]); // Available only in WASM_BIGINT != 2 builds
66+
var ret = bindDynCall('iii', funcPtr)([4, 5]); // Available only in WASM_BIGINT != 2 builds
5367
console.log('iii returned ' + ret);
68+
#else
69+
// Appease test runner and output the same text if not building with WASM_DYNCALLS enabled.
70+
console.log('iii returned ' + wbind(funcPtr)(1, 2));
71+
console.log('iii returned ' + wbind(funcPtr)(2, 3));
72+
console.log('iii returned ' + wbind(funcPtr)(3, 4));
73+
console.log('iii returned ' + wbind(funcPtr)(4, 5));
5474
#endif
5575

5676
// 5. Directly access a function pointer via a static signature (64-bit ABI)
5777
// (this is the fastest way to call a function pointer when the signature is statically known in WASM_BIGINT>0 builds)
58-
var ret = wbind(funcPtr)(2, 3); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
78+
var ret = wbind(funcPtr)(5, 6); // Available in all builds, but in WASM_BIGINT==0 builds cannot be used to call int64 signatures
5979
console.log('iii returned ' + ret);
6080

6181
// 6. Obtain an array form access to the specified signature. (64-bit ABI)

tests/core/test_dyncalls.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
vijdf: i=1,jlo=2,jhi=3,d=4,f=5
2+
vijdf: i=2,jlo=3,jhi=4,d=5,f=6
3+
vijdf: i=3,jlo=4,jhi=5,d=6,f=7
4+
vijdf: i=4,jlo=5,jhi=6,d=7,f=8
5+
vijdf: i=5,jlo=6,jhi=7,d=8,f=9
6+
vijdf: i=6,jlo=7,jhi=8,d=9,f=10
7+
iii: i=1,j=2
8+
iii returned 42
9+
iii: i=2,j=3
10+
iii returned 42
11+
iii: i=3,j=4
12+
iii returned 42
13+
iii: i=4,j=5
14+
iii returned 42
15+
iii: i=5,j=6
16+
iii returned 42
17+
iii: i=6,j=7
18+
iii returned 42

tests/test_core.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8270,9 +8270,17 @@ def test_gl_main_module(self):
82708270
self.set_setting('MAIN_MODULE')
82718271
self.do_runf(path_from_root('tests', 'core', 'test_gl_get_proc_address.c'))
82728272

8273+
@also_with_wasm_bigint
82738274
def test_dyncalls(self):
8274-
self.emcc_args += ['--js-library', path_from_root('tests', 'test_dyncalls.js')]
8275-
self.do_run_in_out_file_test('tests', 'test_dyncalls.c')
8275+
self.emcc_args += ['--js-library', path_from_root('tests', 'core', 'test_dyncalls.js')]
8276+
self.do_run_in_out_file_test('tests', 'core', 'test_dyncalls.c')
8277+
8278+
@no_asan('asan does not yet work in MINIMAL_RUNTIME')
8279+
@also_with_wasm_bigint
8280+
def test_dyncalls_minimal_runtime(self):
8281+
self.set_setting('MINIMAL_RUNTIME')
8282+
self.emcc_args += ['--js-library', path_from_root('tests', 'core', 'test_dyncalls.js')]
8283+
self.do_run_in_out_file_test('tests', 'core', 'test_dyncalls.c')
82768284

82778285

82788286
# Generate tests for everything

0 commit comments

Comments
 (0)