Skip to content

Commit 7550a3a

Browse files
authored
Use direct table access over dynCall in invoke_xx functions (#11979)
This change starts the transition away from dynCall and towards direct use of the wasm table. In particular this change replaces the use of dynCall in invoke_xx functions where possible. dynCall is still needed for functions with i64 in thier signature when WASM_BIGINT is not enabled. When WASM_BIGING is enabled this change removes all use of dynCall by invoke_xx functions.
1 parent b1a7889 commit 7550a3a

11 files changed

+58
-28
lines changed

src/preamble.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,7 @@ function createWasm() {
896896
// then exported.
897897
// TODO: do not create a Memory earlier in JS
898898
wasmMemory = exports['memory'];
899+
wasmTable = exports['__indirect_function_table'];
899900
updateGlobalBufferAndViews(wasmMemory.buffer);
900901
#if ASSERTIONS
901902
writeStackCookie();

src/support.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ function createInvokeFunction(sig) {
301301
return function() {
302302
var sp = stackSave();
303303
try {
304-
return Module['dynCall_' + sig].apply(null, arguments);
304+
return dynCall(sig, arguments[0], Array.prototype.slice.call(arguments, 1));
305305
} catch(e) {
306306
stackRestore(sp);
307307
if (e !== e+0 && e !== 'longjmp') throw e;
@@ -602,24 +602,29 @@ function makeBigInt(low, high, unsigned) {
602602

603603
/** @param {Array=} args */
604604
function dynCall(sig, ptr, args) {
605-
if (args && args.length) {
606-
#if ASSERTIONS
607-
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
608-
assert(args.length === sig.substring(1).replace(/j/g, '--').length);
609-
#endif
610-
#if ASSERTIONS
611-
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
612-
#endif
613-
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
614-
} else {
615-
#if ASSERTIONS
616-
assert(sig.length == 1);
617-
#endif
605+
#if !WASM_BIGINT
606+
// Without WASM_BIGINT support we cannot directly call function with i64 as
607+
// part of their signature, so we rely on the dynCall functions generated by
608+
// wasm-emscripten-finalize
609+
if (sig.indexOf('j') != -1) {
618610
#if ASSERTIONS
619611
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
612+
if (args && args.length) {
613+
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
614+
assert(args.length === sig.substring(1).replace(/j/g, '--').length);
615+
} else {
616+
assert(sig.length == 1);
617+
}
620618
#endif
621-
return Module['dynCall_' + sig].call(null, ptr);
619+
if (args && args.length) {
620+
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
621+
} else {
622+
return Module['dynCall_' + sig].call(null, ptr);
623+
}
622624
}
625+
#endif
626+
627+
return wasmTable.get(ptr).apply(null, args)
623628
}
624629

625630
var tempRet0 = 0;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__indirect_function_table
12
_start
23
memory
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__indirect_function_table
12
_start
23
memory
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__indirect_function_table
12
_start
23
memory
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__indirect_function_table
12
_start
23
memory
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
__indirect_function_table
12
_start
23
memory
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
__indirect_function_table
12
_initialize
23
foo
34
memory

tests/test_other.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7111,7 +7111,7 @@ def test_metadce_mem(self, filename, *args):
71117111
[], [], 128), # noqa
71127112
# argc/argv support code etc. is in the wasm
71137113
'O3_standalone': ('libcxxabi_message.cpp', ['-O3', '-s', 'STANDALONE_WASM'],
7114-
[], [], 198), # noqa
7114+
[], [], 242), # noqa
71157115
})
71167116
def test_metadce_libcxxabi_message(self, filename, *args):
71177117
self.run_metadce_test(filename, *args)

tools/building.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,8 @@ def lld_flags_for_executable(external_symbol_list):
484484
if not Settings.STANDALONE_WASM:
485485
cmd.append('--import-memory')
486486
cmd.append('--import-table')
487+
else:
488+
cmd.append('--export-table')
487489

488490
if Settings.USE_PTHREADS:
489491
cmd.append('--shared-memory')
@@ -1136,7 +1138,10 @@ def add_to_path(dirname):
11361138
logger.error(proc.stderr) # print list of errors (possibly long wall of text if input was minified)
11371139

11381140
# Exit and print final hint to get clearer output
1139-
exit_with_error('closure compiler failed (rc: %d.%s)', proc.returncode, '' if pretty else ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set')
1141+
msg = 'closure compiler failed (rc: %d): %s' % (proc.returncode, shared.shlex_join(cmd))
1142+
if not pretty:
1143+
msg += ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set'
1144+
exit_with_error(msg)
11401145

11411146
if len(proc.stderr.strip()) > 0 and Settings.CLOSURE_WARNINGS != 'quiet':
11421147
# print list of warnings (possibly long wall of text if input was minified)
@@ -1227,6 +1232,12 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info):
12271232
'reaches': [],
12281233
'root': True
12291234
})
1235+
graph.append({
1236+
'export': '__indirect_function_table',
1237+
'name': 'emcc$export$__indirect_function_table',
1238+
'reaches': [],
1239+
'root': True
1240+
})
12301241
# fix wasi imports TODO: support wasm stable with an option?
12311242
WASI_IMPORTS = set([
12321243
'environ_get',

tools/shared.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,28 +1209,34 @@ def make_jscall(sig):
12091209
return ret
12101210

12111211
@staticmethod
1212-
def make_dynCall(sig):
1213-
# Optimize dynCall accesses in the case when not building with dynamic
1214-
# linking enabled.
1215-
if not Settings.MAIN_MODULE and not Settings.SIDE_MODULE:
1216-
return 'dynCall_' + sig
1212+
def make_dynCall(sig, args):
1213+
# wasm2c and asyncify are not yet compatible with direct wasm table calls
1214+
if Settings.ASYNCIFY or Settings.WASM2C or not JS.is_legal_sig(sig):
1215+
args = ','.join(args)
1216+
if not Settings.MAIN_MODULE and not Settings.SIDE_MODULE:
1217+
# Optimize dynCall accesses in the case when not building with dynamic
1218+
# linking enabled.
1219+
return 'dynCall_%s(%s)' % (sig, args)
1220+
else:
1221+
return 'Module["dynCall_%s"](%s)' % (sig, args)
12171222
else:
1218-
return 'Module["dynCall_' + sig + '"]'
1223+
return 'wasmTable.get(%s)(%s)' % (args[0], ','.join(args[1:]))
12191224

12201225
@staticmethod
12211226
def make_invoke(sig, named=True):
12221227
legal_sig = JS.legalize_sig(sig) # TODO: do this in extcall, jscall?
1223-
args = ','.join(['a' + str(i) for i in range(1, len(legal_sig))])
1224-
args = 'index' + (',' if args else '') + args
1228+
args = ['index'] + ['a' + str(i) for i in range(1, len(legal_sig))]
12251229
ret = 'return ' if sig[0] != 'v' else ''
1226-
body = '%s%s(%s);' % (ret, JS.make_dynCall(sig), args)
1230+
body = '%s%s;' % (ret, JS.make_dynCall(sig, args))
12271231
# C++ exceptions are numbers, and longjmp is a string 'longjmp'
12281232
if Settings.SUPPORT_LONGJMP:
12291233
rethrow = "if (e !== e+0 && e !== 'longjmp') throw e;"
12301234
else:
12311235
rethrow = "if (e !== e+0) throw e;"
12321236

1233-
ret = '''function%s(%s) {
1237+
name = (' invoke_' + sig) if named else ''
1238+
ret = '''\
1239+
function%s(%s) {
12341240
var sp = stackSave();
12351241
try {
12361242
%s
@@ -1239,7 +1245,8 @@ def make_invoke(sig, named=True):
12391245
%s
12401246
_setThrew(1, 0);
12411247
}
1242-
}''' % ((' invoke_' + sig) if named else '', args, body, rethrow)
1248+
}''' % (name, ','.join(args), body, rethrow)
1249+
12431250
return ret
12441251

12451252
@staticmethod

0 commit comments

Comments
 (0)