clarify the extra optimization for function pointers that we do in shared modules by default, by creating an EMULATED_FUNCTION_POINTERS=2 setting, in which we optimize, and 1 does not, and still allows for full flexibility in manipulating the function table from JS
This commit is contained in:
Родитель
55b5f3c60d
Коммит
b9c24785c3
3
emcc
3
emcc
|
@ -953,7 +953,8 @@ try:
|
|||
|
||||
if shared.Settings.RELOCATABLE:
|
||||
assert shared.Settings.GLOBAL_BASE < 1
|
||||
shared.Settings.EMULATED_FUNCTION_POINTERS = 1
|
||||
if shared.Settings.EMULATED_FUNCTION_POINTERS == 0:
|
||||
shared.Settings.EMULATED_FUNCTION_POINTERS = 2 # by default, use optimized function pointer emulation
|
||||
shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = shared.Settings.WARN_ON_UNDEFINED_SYMBOLS = 0
|
||||
if not shared.Settings.SIDE_MODULE:
|
||||
shared.Settings.EXPORT_ALL = 1
|
||||
|
|
|
@ -617,7 +617,11 @@ function ftCall_%s(%s) {%s
|
|||
coercions = ';'.join(['ptr = ptr | 0'] + ['p%d = %s' % (p, shared.JS.make_coercion('p%d' % p, sig[p+1], settings)) for p in range(len(sig)-1)]) + ';'
|
||||
mini_coerced_params = make_coerced_params(sig)
|
||||
maybe_return = '' if sig[0] == 'v' else 'return'
|
||||
funcs_js.append(make_func('mftCall_' + sig, 'if (((ptr|0) >= (fb|0)) & ((ptr|0) < (fb + {{{ FTM_' + sig + ' }}} | 0))) { ' + maybe_return + ' ' + shared.JS.make_coercion('FUNCTION_TABLE_' + sig + '[(ptr-fb)&{{{ FTM_' + sig + ' }}}](' + mini_coerced_params + ')', sig[0], settings) + '; ' + ('return;' if sig[0] == 'v' else '') + ' }' + maybe_return + ' ' + shared.JS.make_coercion('ftCall_' + sig + '(' + coerced_params + ')', sig[0], settings) + ';', params, coercions) + '\n')
|
||||
if settings['EMULATED_FUNCTION_POINTERS'] == 1:
|
||||
body = maybe_return + ' ' + shared.JS.make_coercion('ftCall_' + sig + '(' + coerced_params + ')', sig[0], settings) + ';'
|
||||
else:
|
||||
body = 'if (((ptr|0) >= (fb|0)) & ((ptr|0) < (fb + {{{ FTM_' + sig + ' }}} | 0))) { ' + maybe_return + ' ' + shared.JS.make_coercion('FUNCTION_TABLE_' + sig + '[(ptr-fb)&{{{ FTM_' + sig + ' }}}](' + mini_coerced_params + ')', sig[0], settings) + '; ' + ('return;' if sig[0] == 'v' else '') + ' }' + maybe_return + ' ' + shared.JS.make_coercion('ftCall_' + sig + '(' + coerced_params + ')', sig[0], settings) + ';'
|
||||
funcs_js.append(make_func('mftCall_' + sig, body, params, coercions) + '\n')
|
||||
|
||||
def quote(prop):
|
||||
if settings['USE_CLOSURE_COMPILER'] == 2:
|
||||
|
|
|
@ -176,6 +176,16 @@ var EMULATED_FUNCTION_POINTERS = 0; // By default we implement function pointers
|
|||
// function tables, which is very fast. With this option,
|
||||
// we implement them more flexibly by emulating them: we
|
||||
// call out into JS, which handles the function tables.
|
||||
// 1: Full emulation. This means you can modify the
|
||||
// table in JS fully dynamically, not just add to
|
||||
// the end.
|
||||
// 2: Optimized emulation. Assumes once something is
|
||||
// added to the table, it will not change. This allows
|
||||
// dynamic linking while keeping performance fast,
|
||||
// as we can do a fast call into the internal table
|
||||
// if the fp is in the right range. Shared modules
|
||||
// (MAIN_MODULE, SIDE_MODULE) do this by default.
|
||||
// This requires RELOCATABLE to be set.
|
||||
var EMULATE_FUNCTION_POINTER_CASTS = 0; // Allows function pointers to be cast, wraps each
|
||||
// call of an incorrect type with a runtime correction.
|
||||
// This adds overhead and should not be used normally.
|
||||
|
|
|
@ -465,7 +465,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
|
|||
|
||||
# extra coverages
|
||||
for emulate_casts in [0, 1]:
|
||||
for emulate_fps in [0, 1]:
|
||||
for emulate_fps in [0, 1, 2]:
|
||||
print emulate_casts, emulate_fps
|
||||
Settings.EMULATE_FUNCTION_POINTER_CASTS = emulate_casts
|
||||
Settings.EMULATED_FUNCTION_POINTERS = emulate_fps
|
||||
|
|
|
@ -4933,6 +4933,57 @@ int main(int argc, char** argv) {
|
|||
test(['-O' + str(opts)], 'no visible function tables')
|
||||
test(['-O' + str(opts), '-s', 'EMULATED_FUNCTION_POINTERS=1'], 'function table: ')
|
||||
|
||||
def test_emulated_function_pointers_2(self):
|
||||
src = r'''
|
||||
#include <emscripten.h>
|
||||
typedef void (*fp)();
|
||||
void one() { EM_ASM( Module.print('one') ); }
|
||||
void two() { EM_ASM( Module.print('two') ); }
|
||||
void test() {
|
||||
volatile fp f = one;
|
||||
f();
|
||||
f = two;
|
||||
f();
|
||||
}
|
||||
int main(int argc, char **argv) {
|
||||
test();
|
||||
// swap them!
|
||||
EM_ASM_INT({
|
||||
var one = $0;
|
||||
var two = $1;
|
||||
if (typeof FUNCTION_TABLE_v === 'undefined') {
|
||||
Module.print('no');
|
||||
return;
|
||||
}
|
||||
var temp = FUNCTION_TABLE_v[one];
|
||||
FUNCTION_TABLE_v[one] = FUNCTION_TABLE_v[two];
|
||||
FUNCTION_TABLE_v[two] = temp;
|
||||
}, (int)&one, (int)&two);
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
open('src.c', 'w').write(src)
|
||||
|
||||
flipped = 'one\ntwo\ntwo\none\n'
|
||||
unchanged = 'one\ntwo\none\ntwo\n'
|
||||
no_table = 'one\ntwo\nno\none\ntwo\n'
|
||||
|
||||
def test(args, expected):
|
||||
print args, expected.replace('\n', ' ')
|
||||
Popen([PYTHON, EMCC, 'src.c'] + args).communicate()
|
||||
self.assertContained(expected, run_js(self.in_dir('a.out.js')))
|
||||
|
||||
for opts in [0, 1, 2]:
|
||||
test(['-O' + str(opts)], no_table)
|
||||
test(['-O' + str(opts), '-s', 'EMULATED_FUNCTION_POINTERS=1'], flipped)
|
||||
test(['-O' + str(opts), '-s', 'EMULATED_FUNCTION_POINTERS=2'], flipped)
|
||||
test(['-O' + str(opts), '-s', 'EMULATED_FUNCTION_POINTERS=1', '-s', 'RELOCATABLE=1'], flipped)
|
||||
test(['-O' + str(opts), '-s', 'EMULATED_FUNCTION_POINTERS=2', '-s', 'RELOCATABLE=1'], unchanged) # with both of those, we optimize and you cannot flip them
|
||||
test(['-O' + str(opts), '-s', 'MAIN_MODULE=1'], unchanged) # default for modules is optimized
|
||||
test(['-O' + str(opts), '-s', 'MAIN_MODULE=1', '-s', 'EMULATED_FUNCTION_POINTERS=2'], unchanged)
|
||||
test(['-O' + str(opts), '-s', 'MAIN_MODULE=1', '-s', 'EMULATED_FUNCTION_POINTERS=1'], flipped) # but you can disable that
|
||||
|
||||
def test_file_packager_eval(self):
|
||||
BAD = 'Module = eval('
|
||||
src = path_from_root('tests', 'hello_world.c')
|
||||
|
|
Загрузка…
Ссылка в новой задаче