Skip to content

Optimize makeDynCall to avoid dynamic dynCall where possible #12741

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,6 @@ def filter_out_duplicate_dynamic_libs(inputs):
# See: https://github.com/emscripten-core/emscripten/issues/12065
# See: https://github.com/emscripten-core/emscripten/issues/12066
shared.Settings.USE_LEGACY_DYNCALLS = 1
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$getDynCaller']
shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_get_base',
'_emscripten_stack_get_end',
'_emscripten_stack_set_limits']
Expand Down Expand Up @@ -1618,18 +1617,12 @@ def filter_out_duplicate_dynamic_libs(inputs):
if not shared.Settings.MINIMAL_RUNTIME or shared.Settings.EXIT_RUNTIME:
# MINIMAL_RUNTIME only needs callRuntimeCallbacks in certain cases, but the normal runtime
# always does.
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$callRuntimeCallbacks', '$dynCall']
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$callRuntimeCallbacks']

if shared.Settings.USE_PTHREADS:
# memalign is used to ensure allocated thread stacks are aligned.
shared.Settings.EXPORTED_FUNCTIONS += ['_memalign']

# dynCall is used to call pthread entry points in worker.js (as
# metadce does not consider worker.js, which is external, we must
# consider it an export, i.e., one which can never be removed).
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$dynCall']
shared.Settings.EXPORTED_FUNCTIONS += ['dynCall']

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

Expand All @@ -1642,6 +1635,7 @@ def include_and_export(name):
shared.Settings.EXPORTED_FUNCTIONS += [name]

include_and_export('establishStackSpace')
include_and_export('invokeEntryPoint')
if not shared.Settings.MINIMAL_RUNTIME:
# noExitRuntime does not apply to MINIMAL_RUNTIME.
include_and_export('getNoExitRuntime')
Expand Down
2 changes: 1 addition & 1 deletion src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -3727,7 +3727,7 @@ LibraryManager.library = {
},
#endif

$dynCall: function (sig, ptr, args) {
$dynCall: function(sig, ptr, args) {
#if USE_LEGACY_DYNCALLS
return dynCallLegacy(sig, ptr, args);
#else
Expand Down
10 changes: 4 additions & 6 deletions src/library_browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1105,10 +1105,9 @@ var LibraryBrowser = {
},

// TODO: currently not callable from a pthread, but immediately calls onerror() if not on main thread.
emscripten_async_load_script__deps: ['$getFuncWrapper'],
emscripten_async_load_script: function(url, onload, onerror) {
onload = getFuncWrapper(onload, 'v');
onerror = getFuncWrapper(onerror, 'v');
onload = {{{ makeDynCall('v', 'onload') }}};
onerror = {{{ makeDynCall('v', 'onerror') }}};

#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) {
Expand Down Expand Up @@ -1197,7 +1196,7 @@ var LibraryBrowser = {
emscripten_set_main_loop__deps: ['$setMainLoop'],
emscripten_set_main_loop__docs: '/** @param {number|boolean=} noSetTiming */',
emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop, arg, noSetTiming) {
var browserIterationFunc = function() { {{{ makeDynCall('v', 'func') }}}(); };
var browserIterationFunc = {{{ makeDynCall('v', 'func') }}};
setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop, arg, noSetTiming);
},

Expand Down Expand Up @@ -1519,7 +1518,6 @@ var LibraryBrowser = {
Browser.workers[id] = null;
},

emscripten_call_worker__deps: ['$getFuncWrapper'],
emscripten_call_worker__proxy: 'sync',
emscripten_call_worker__sig: 'viiiiii',
emscripten_call_worker: function(id, funcName, data, size, callback, arg) {
Expand All @@ -1531,7 +1529,7 @@ var LibraryBrowser = {
if (callback) {
callbackId = info.callbacks.length;
info.callbacks.push({
func: getFuncWrapper(callback, 'viii'),
func: {{{ makeDynCall('viii', 'callback') }}},
arg: arg
});
info.awaited++;
Expand Down
4 changes: 4 additions & 0 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -1418,6 +1418,10 @@ var LibraryPThread = {
return noExitRuntime;
},

$invokeEntryPoint: function(ptr, arg) {
return {{{ makeDynCall('ii', 'ptr') }}}(arg);
},

// When using postMessage to send an object, it is processed by the structured clone algorithm.
// The prototype, and hence methods, on that object is then lost. This function adds back the lost prototype.
// This does not work with nested objects that has prototypes, but it suffices for WasmSourceMap and WasmOffsetConverter.
Expand Down
12 changes: 11 additions & 1 deletion src/parseTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,17 @@ function makeDynCall(sig, funcPtr) {
}
}
if (USE_LEGACY_DYNCALLS) {
return `getDynCaller("${sig}", ${funcPtr})`;
let dyncall = exportedAsmFunc(`dynCall_${sig}`)
if (sig.length > 1) {
let args = [];
for (let i = 1; i < sig.length; ++i) {
args.push(`a${i}`);
}
args = args.join(', ');
return `(function(${args}) { ${dyncall}.apply(null, [${funcPtr}, ${args}]); })`;
} else {
return `(function() { ${dyncall}.call(null, ${funcPtr}); })`;
}
} else {
return `wasmTable.get(${funcPtr})`;
}
Expand Down
1 change: 0 additions & 1 deletion src/postamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ function initRuntime(asm) {
// Export needed variables that worker.js needs to Module.
Module['_emscripten_tls_init'] = _emscripten_tls_init;
Module['HEAPU32'] = HEAPU32;
Module['dynCall'] = dynCall;
Module['__emscripten_thread_init'] = __emscripten_thread_init;
Module['_pthread_self'] = _pthread_self;

Expand Down
2 changes: 1 addition & 1 deletion src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ this.onmessage = function(e) {
// enable that to work. If you find the following line to crash, either change the signature
// to "proper" void *ThreadMain(void *arg) form, or try linking with the Emscripten linker
// flag -s EMULATE_FUNCTION_POINTER_CASTS=1 to add in emulation for this x86 ABI extension.
var result = Module['dynCall']('ii', e.data.start_routine, [e.data.arg]);
var result = Module['invokeEntryPoint'](e.data.start_routine, e.data.arg);

#if STACK_OVERFLOW_CHECK
Module['checkStackCookie']();
Expand Down
2 changes: 1 addition & 1 deletion tools/ports/sdl2.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def clear(ports, settings, shared):


def process_dependencies(settings):
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$autoResumeAudioContext']
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$autoResumeAudioContext', '$dynCall']


def process_args(ports):
Expand Down