Skip to content

Commit

Permalink
Revise the API.
Browse files Browse the repository at this point in the history
  • Loading branch information
juj committed Jan 20, 2021
1 parent 3563c51 commit aa5170b
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 254 deletions.
2 changes: 1 addition & 1 deletion emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ def default_setting(name, new_default):
exit_with_error('Invalid option -s CLOSURE_WARNINGS=%s specified! Allowed values are "quiet", "warn" or "error".' % shared.Settings.CLOSURE_WARNINGS)

# Calling function pointers from JS libraries is default runtime functionality, so always include the functionality. (to be DCEd if not used)
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$dynCall', '$bindDynCall', '$bindDynCallArray']
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$dynCall']

if shared.Settings.MAIN_MODULE:
assert not shared.Settings.SIDE_MODULE
Expand Down
10 changes: 6 additions & 4 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ def make_wasm_table_static_dyncaller(func):
i += 1
ptr_args = ('ptr, ' + args) if len(args) > 0 else 'ptr'

return 'function ' + func + '(' + ptr_args + ') { ' + ret + 'wasmTable.get(ptr)(' + args + '); }'
dyncall = ('dyncalls["' + sig + '"]') if shared.Settings.MINIMAL_RUNTIME else ('Module["' + func + '"]')
wasmTableGet = 'wasmTableGet' if shared.Settings.SHRINK_LEVEL == 0 else 'wasmTable.get'
return 'function ' + func + '(' + ptr_args + ') { ' + ret + dyncall + '(' + ptr_args + '); }\n'


def compute_minimal_runtime_initializer_and_exports(post, exports, receiving):
Expand All @@ -62,7 +64,7 @@ def compute_minimal_runtime_initializer_and_exports(post, exports, receiving):

static_dyncall_sig_functions = ''

if shared.Settings.USE_LEGACY_DYNCALLS:
if shared.Settings.USE_LEGACY_DYNCALLS or not shared.Settings.WASM_BIGINT:
if len([x for x in exports_that_are_not_initializers if x.startswith('dynCall_')]) > 0:
exports_that_are_not_initializers += ['dynCalls = {}']
else:
Expand Down Expand Up @@ -726,7 +728,7 @@ def create_receiving(exports):
return ''

exports_that_are_not_initializers = [x for x in exports if x != WASM_INIT_FUNC]
if not shared.Settings.USE_LEGACY_DYNCALLS:
if not shared.Settings.USE_LEGACY_DYNCALLS and shared.Settings.WASM_BIGINT:
exports_that_are_not_initializers = [x for x in exports_that_are_not_initializers if not x.startswith('dynCall_')]

receiving = []
Expand All @@ -743,7 +745,7 @@ def create_receiving(exports):
# _main = asm["_main"];
for s in exports_that_are_not_initializers:
mangled = asmjs_mangle(s)
dynCallAssignment = ('dynCalls["' + s.replace('dynCall_', '') + '"] = ') if shared.Settings.USE_LEGACY_DYNCALLS and mangled.startswith('dynCall_') else ''
dynCallAssignment = ('dynCalls["' + s.replace('dynCall_', '') + '"] = ') if shared.Settings.USE_LEGACY_DYNCALLS or not shared.Settings.WASM_BIGINT and mangled.startswith('dynCall_') else ''
receiving += [dynCallAssignment + mangled + ' = asm["' + s + '"];']
else:
if shared.Settings.MINIMAL_RUNTIME:
Expand Down
119 changes: 54 additions & 65 deletions src/library_dyncall.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,67 @@
mergeInto(LibraryManager.library, {
$bindDynCall: function(funcPtr) {
{{{ (function() { global.wbind = function() { return SHRINK_LEVEL == 0 ? 'wbind' : 'wasmTable.get'; }; return null; })(); }}}
{{{ (function() { global.getDynCaller = function(sig) { return MINIMAL_RUNTIME ? `dynCalls[${sig}]` : `Module["dynCall_${sig}]`; }; return null; })(); }}}

#if SHRINK_LEVEL == 0
// A mirror copy of contents of wasmTable in JS side, to avoid relatively
// slow wasmTable.get() call. Only used when not compiling with -Os or -Oz.
_wasmTableMirror: [],

$wbind__deps: ['_wasmTableMirror'],
$wbind: function(funcPtr) {
var func = __wasmTableMirror[funcPtr];
if (!func) {
if (funcPtr >= __wasmTableMirror.length) __wasmTableMirror.length = funcPtr + 1;
__wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr);
}
return func;
},

$dynCall__deps: ['$wbind'],
$bindDynCall__deps: ['$wbind'],
$wbindArray__deps: ['$wbind'],
#else
$wbind: function(funcPtr) {
// In -Os and -Oz builds, do not implement a JS side wasm table mirror for small
// code size, but directly access wasmTable, which is a bit slower.
return wasmTable.get(funcPtr);
},
#endif

$bindDynCallArray: function(funcPtr) {
var func = wasmTable.get(funcPtr);
return func.length ? function(args) {
return func.apply(null, args);
} : function() { return func(); }
// A helper that binds a wasm function into a form that can be called by passing all
// the parameters in an array, e.g. wbindArray(func)([param1, param2, ..., paramN]).
$wbindArray: function(funcPtr) {
var func = {{{wbind()}}}(funcPtr);
return func.length
? function(args) { return func.apply(null, args); }
: function() { return func(); }
},

#if USE_LEGACY_DYNCALLS || !WASM_BIGINT
$dynCallLegacy: function(sig, ptr, args) {
#if ASSERTIONS
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
if (args && args.length) {
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
assert(args.length === sig.substring(1).replace(/j/g, '--').length);
} else {
assert(sig.length == 1);
}
#endif
if (args && args.length) {
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
}
return Module['dynCall_' + sig].call(null, ptr);
// A helper that returns a function that can be used to invoke function pointers, i.e.
// getDynCaller('vi')(funcPtr, myInt);
$getDynCaller: function(sig, funcPtr) {
return {{{getDynCaller('sig')}}};
},

// Used in library code to get JS function from wasm function pointer.
// All callers should use direct table access where possible and only fall
// back to this function if needed.
$getDynCaller__deps: ['$dynCall'],
$getDynCaller: function(sig, ptr) {
#if !USE_LEGACY_DYNCALLS
assert(sig.indexOf('j') >= 0, 'getDynCaller should only be called with i64 sigs')
#endif
var argCache = [];
return function() {
argCache.length = arguments.length;
for (var i = 0; i < arguments.length; i++) {
argCache[i] = arguments[i];
}
return dynCall(sig, ptr, argCache);
};
$bindDynCall: function(sig, funcPtr) {
// For int64 signatures, use the dynCall_sig dispatch mechanism.
if (sig.includes('j')) return function(args) {
return {{{getDynCaller('sig')}}}.apply(null, [funcPtr].concat(args));
}
// For non-int64 signatures, invoke via the wasm table.
var func = {{{wbind()}}}(funcPtr);
return func.length
? function(args) { return func.apply(null, args); }
: function() { return func(); }
},
#endif

// $dynCall__deps: ['$dynCallLegacy'],
$dynCall: function(sig, ptr, args) {
#if USE_LEGACY_DYNCALLS
#if MINIMAL_RUNTIME
var func = dynCalls[sig];
#else
var func = Module['dynCall_'+sig];
#endif
return args ? func.apply(null, [ptr].concat(args)) : func(ptr);
#else
#if !WASM_BIGINT
// Without WASM_BIGINT support we cannot directly call function with i64 as
// part of thier signature, so we rely the dynCall functions generated by
// wasm-emscripten-finalize
if (sig.indexOf('j') != -1) {
#if MINIMAL_RUNTIME
var func = dynCalls[sig];
#else
var func = Module['dynCall_'+sig];
#endif
return args ? func.apply(null, [ptr].concat(args)) : func(ptr);
$dynCall: function(sig, funcPtr, args) {
// For int64 signatures, use the dynCall_sig dispatch mechanism.
if (sig.includes('j')) {
return {{{getDynCaller('sig')}}}.apply(null, [funcPtr].concat(args));
}
#endif
#if ASSERTIONS
assert(wasmTable.get(ptr), 'missing table entry in dynCall: ' + ptr);
#endif
return wasmTable.get(ptr).apply(null, args)
#endif

// For non-int64 signatures, invoke via the wasm table.
return {{{wbind()}}}(funcPtr).apply(null, args);
}
});
Loading

0 comments on commit aa5170b

Please sign in to comment.