Skip to content

Commit d2df01d

Browse files
committed
Use direct table access over dynCall where possible
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 b8fd9a0 commit d2df01d

File tree

6 files changed

+57
-33
lines changed

6 files changed

+57
-33
lines changed

emcc.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,10 +1576,11 @@ def check(input_file):
15761576
# memalign is used to ensure allocated thread stacks are aligned.
15771577
shared.Settings.EXPORTED_FUNCTIONS += ['_memalign', '_malloc']
15781578

1579-
# dynCall_ii is used to call pthread entry points in worker.js (as
1580-
# metadce does not consider worker.js, which is external, we must
1581-
# consider it a user export, i.e., one which can never be removed).
1582-
building.user_requested_exports += ['dynCall_ii']
1579+
if not shared.Settings.WASM:
1580+
# dynCall_ii is used to call pthread entry points in worker.js (as
1581+
# metadce does not consider worker.js, which is external, we must
1582+
# consider it a user export, i.e., one which can never be removed).
1583+
building.user_requested_exports += ['dynCall_ii']
15831584

15841585
if shared.Settings.MINIMAL_RUNTIME:
15851586
building.user_requested_exports += ['exit']

src/preamble.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,7 @@ function callRuntimeCallbacks(callbacks) {
428428
}
429429
var func = callback.func;
430430
if (typeof func === 'number') {
431-
if (callback.arg === undefined) {
432-
Module['dynCall_v'](func);
433-
} else {
434-
Module['dynCall_vi'](func, callback.arg);
435-
}
431+
dynCallDirect(func, [callback.arg]);
436432
} else {
437433
func(callback.arg === undefined ? null : callback.arg);
438434
}
@@ -902,6 +898,7 @@ function createWasm() {
902898
// then exported.
903899
// TODO: do not create a Memory earlier in JS
904900
wasmMemory = exports['memory'];
901+
wasmTable = exports['__indirect_function_table'];
905902
updateGlobalBufferAndViews(wasmMemory.buffer);
906903
#if ASSERTIONS
907904
writeStackCookie();

src/preamble_minimal.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ var wasmOffsetConverter;
200200
#include "wasm_offset_converter.js"
201201
#endif
202202

203+
/** @param {Array=} args */
204+
function dynCallDirect(ptr, args) {
205+
return wasmTable.get(ptr).apply(null, args);
206+
}
207+
203208
#if EXIT_RUNTIME
204209

205210
function callRuntimeCallbacks(callbacks) {
@@ -211,11 +216,7 @@ function callRuntimeCallbacks(callbacks) {
211216
}
212217
var func = callback.func;
213218
if (typeof func === 'number') {
214-
if (callback.arg === undefined) {
215-
dynCall_v(func);
216-
} else {
217-
dynCall_vi(func, callback.arg);
218-
}
219+
dynCallDirect(func, [callback.arg]);
219220
} else {
220221
func(callback.arg === undefined ? null : callback.arg);
221222
}

src/support.js

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -577,16 +577,16 @@ function getFuncWrapper(func, sig) {
577577
if (!sigCache[func]) {
578578
// optimize away arguments usage in common cases
579579
if (sig.length === 1) {
580-
sigCache[func] = function dynCall_wrapper() {
580+
sigCache[func] = function() {
581581
return dynCall(sig, func);
582582
};
583583
} else if (sig.length === 2) {
584-
sigCache[func] = function dynCall_wrapper(arg) {
584+
sigCache[func] = function(arg) {
585585
return dynCall(sig, func, [arg]);
586586
};
587587
} else {
588588
// general case
589-
sigCache[func] = function dynCall_wrapper() {
589+
sigCache[func] = function() {
590590
return dynCall(sig, func, Array.prototype.slice.call(arguments));
591591
};
592592
}
@@ -600,26 +600,38 @@ function makeBigInt(low, high, unsigned) {
600600
return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0));
601601
}
602602

603+
/** @param {Array=} args */
604+
function dynCallDirect(ptr, args) {
605+
return wasmTable.get(ptr).apply(null, args);
606+
}
607+
603608
/** @param {Array=} args */
604609
function dynCall(sig, ptr, args) {
605-
if (args && args.length) {
606610
#if ASSERTIONS
611+
if (args && args.length) {
612+
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
613+
assert(args.length === sig.substring(1).replace(/j/g, '--').length);
607614
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
608615
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));
614616
} else {
615-
#if ASSERTIONS
616617
assert(sig.length == 1);
618+
}
617619
#endif
620+
621+
#if !WASM_BIGINT
622+
if (sig.indexOf('j') != -1) {
618623
#if ASSERTIONS
619-
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
624+
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
620625
#endif
621-
return Module['dynCall_' + sig].call(null, ptr);
626+
if (args && args.length) {
627+
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
628+
} else {
629+
return Module['dynCall_' + sig].call(null, ptr);
630+
}
622631
}
632+
#endif
633+
634+
dynCallDirect(ptr, args);
623635
}
624636

625637
var tempRet0 = 0;

tools/building.py

Lines changed: 2 additions & 0 deletions
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')

tools/shared.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,25 +1212,35 @@ def make_jscall(sig):
12121212
def make_dynCall(sig):
12131213
# Optimize dynCall accesses in the case when not building with dynamic
12141214
# linking enabled.
1215-
if not Settings.MAIN_MODULE and not Settings.SIDE_MODULE:
1216-
return 'dynCall_' + sig
1217-
else:
1215+
if Settings.MAIN_MODULE or Settings.SIDE_MODULE:
12181216
return 'Module["dynCall_' + sig + '"]'
1217+
else:
1218+
return 'dynCall_' + sig
12191219

12201220
@staticmethod
12211221
def make_invoke(sig, named=True):
12221222
legal_sig = JS.legalize_sig(sig) # TODO: do this in extcall, jscall?
12231223
args = ','.join(['a' + str(i) for i in range(1, len(legal_sig))])
1224-
args = 'index' + (',' if args else '') + args
12251224
ret = 'return ' if sig[0] != 'v' else ''
1226-
body = '%s%s(%s);' % (ret, JS.make_dynCall(sig), args)
1225+
args = 'index' + (',' if args else '') + args
1226+
if Settings.WASM_BIGINT or 'j' not in sig:
1227+
new_args = ['a' + str(i) for i in range(1, len(legal_sig))]
1228+
for i in range(len(sig) - 1):
1229+
if sig[i+1] == 'j':
1230+
new_args[i] = 'BigInt(%s)' % new_args[i]
1231+
new_args = ','.join(new_args)
1232+
body = '%sdynCallDirect(index, [%s]);' % (ret, new_args)
1233+
else:
1234+
body = '%s%s(%s);' % (ret, JS.make_dynCall(sig), args)
12271235
# C++ exceptions are numbers, and longjmp is a string 'longjmp'
12281236
if Settings.SUPPORT_LONGJMP:
12291237
rethrow = "if (e !== e+0 && e !== 'longjmp') throw e;"
12301238
else:
12311239
rethrow = "if (e !== e+0) throw e;"
12321240

1233-
ret = '''function%s(%s) {
1241+
name = (' invoke_' + sig) if named else ''
1242+
ret = '''\
1243+
function%s(%s) {
12341244
var sp = stackSave();
12351245
try {
12361246
%s
@@ -1239,7 +1249,8 @@ def make_invoke(sig, named=True):
12391249
%s
12401250
_setThrew(1, 0);
12411251
}
1242-
}''' % ((' invoke_' + sig) if named else '', args, body, rethrow)
1252+
}''' % (name, args, body, rethrow)
1253+
12431254
return ret
12441255

12451256
@staticmethod

0 commit comments

Comments
 (0)