diff --git a/emscripten.py b/emscripten.py index 0f3a8f46b6e2..62d51c62bd35 100644 --- a/emscripten.py +++ b/emscripten.py @@ -493,14 +493,13 @@ def emscript(infile, outfile, memfile, temp_files, DEBUG): report_missing_symbols(set([asmjs_mangle(f) for f in exports]), pre) - asm_consts, asm_const_funcs = create_asm_consts_wasm(forwarded_json, metadata) + asm_consts = create_asm_consts_wasm(forwarded_json, metadata) em_js_funcs = create_em_js(forwarded_json, metadata) asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts] asm_const_map = 'var ASM_CONSTS = {\n ' + ', \n '.join(asm_const_pairs) + '\n};\n' pre = pre.replace( '// === Body ===', ('// === Body ===\n\n' + asm_const_map + - asstr('\n'.join(asm_const_funcs)) + '\n'.join(em_js_funcs) + '\n')) pre = apply_table(pre) outfile.write(pre) @@ -585,6 +584,7 @@ def finalize_wasm(temp_files, infile, outfile, memfile, DEBUG): args.append('--pass-arg=legalize-js-interface-export-originals') if shared.Settings.DEBUG_LEVEL >= 3: args.append('--dwarf') + args.append('--minimize-wasm-changes') stdout = building.run_binaryen_command('wasm-emscripten-finalize', infile=base_wasm, outfile=wasm, @@ -606,7 +606,6 @@ def finalize_wasm(temp_files, infile, outfile, memfile, DEBUG): def create_asm_consts_wasm(forwarded_json, metadata): asm_consts = {} - all_sigs = [] for k, v in metadata['asmConsts'].items(): const, sigs, call_types = v const = asstr(const) @@ -621,47 +620,9 @@ def create_asm_consts_wasm(forwarded_json, metadata): args.append('$' + str(i)) const = 'function(' + ', '.join(args) + ') {' + const + '}' asm_consts[int(k)] = const - for sig, call_type in zip(sigs, call_types): - all_sigs.append((sig, call_type)) - - asm_const_funcs = [] - - for sig, call_type in set(all_sigs): - const_name = '_emscripten_asm_const_' + call_type + sig - forwarded_json['Functions']['libraryFunctions'][const_name] = 1 - - preamble = '' - if shared.Settings.USE_PTHREADS: - sync_proxy = call_type == 'sync_on_main_thread_' - async_proxy = call_type == 'async_on_main_thread_' - proxied = sync_proxy or async_proxy - if proxied: - # In proxied function calls, positive integers 1, 2, 3, ... denote pointers - # to regular C compiled functions. Negative integers -1, -2, -3, ... denote - # indices to EM_ASM() blocks, so remap the EM_ASM() indices from 0, 1, 2, - # ... over to the negative integers starting at -1. - preamble += ('\n if (ENVIRONMENT_IS_PTHREAD) { ' + - proxy_debug_print(sync_proxy) + - 'return _emscripten_proxy_to_main_thread_js.apply(null, ' + - '[-1 - code, ' + str(int(sync_proxy)) + '].concat(args)) }') - - if shared.Settings.RELOCATABLE: - preamble += '\n code -= %s;\n' % shared.Settings.GLOBAL_BASE - - # EM_ASM functions are variadic, receiving the actual arguments as a buffer - # in memory. the last parameter (argBuf) points to that data. We need to - # alwayd un-variadify that, as in the async case this is a stack allocation - # that LLVM made, which may go away before the main thread gets the message. - # the readAsmConstArgs helper does so. - asm_const_funcs.append(r''' -function %s(code, sigPtr, argbuf) { - var args = readAsmConstArgs(sigPtr, argbuf); -%s - return ASM_CONSTS[code].apply(null, args); -}''' % (const_name, preamble)) asm_consts = [(key, value) for key, value in asm_consts.items()] asm_consts.sort() - return asm_consts, asm_const_funcs + return asm_consts def create_em_js(forwarded_json, metadata): @@ -815,13 +776,9 @@ def create_sending_wasm(invoke_funcs, forwarded_json, metadata): if shared.Settings.SAFE_HEAP: basic_funcs += ['segfault', 'alignfault'] - em_asm_sigs = [zip(sigs, call_types) for _, sigs, call_types in metadata['asmConsts'].values()] - # flatten em_asm_sigs - em_asm_sigs = [sig for sigs in em_asm_sigs for sig in sigs] - em_asm_funcs = ['_emscripten_asm_const_' + call_type + sig for sig, call_type in em_asm_sigs] em_js_funcs = list(metadata['emJsFuncs'].keys()) declared_items = ['_' + item for item in metadata['declares']] - send_items = set(basic_funcs + invoke_funcs + em_asm_funcs + em_js_funcs + declared_items) + send_items = set(basic_funcs + invoke_funcs + em_js_funcs + declared_items) def fix_import_name(g): if g.startswith('Math_'): diff --git a/src/library.js b/src/library.js index 7d97c3300fb4..b847802e9780 100644 --- a/src/library.js +++ b/src/library.js @@ -3981,6 +3981,49 @@ LibraryManager.library = { return readAsmConstArgsArray; }, + emscripten_asm_const_int__sig: 'iiii', + emscripten_asm_const_int: function(code, sigPtr, argbuf) { +#if RELOCATABLE + code -= {{{ GLOBAL_BASE }}}; +#endif + var args = readAsmConstArgs(sigPtr, argbuf); + return ASM_CONSTS[code].apply(null, args); + }, + emscripten_asm_const_double: 'emscripten_asm_const_int', + $mainThreadEM_ASM: function(code, sigPtr, argbuf, sync) { +#if RELOCATABLE + code -= {{{ GLOBAL_BASE }}}; +#endif + var args = readAsmConstArgs(sigPtr, argbuf); +#if USE_PTHREADS + if (ENVIRONMENT_IS_PTHREAD) { + // EM_ASM functions are variadic, receiving the actual arguments as a buffer + // in memory. the last parameter (argBuf) points to that data. We need to + // always un-variadify that, *before proxying*, as in the async case this + // is a stack allocation that LLVM made, which may go away before the main + // thread gets the message. For that reason we handle proxying *after* the + // call to readAsmConstArgs, and therefore we do that manually here instead + // of using __proxy. (And dor simplicity, do the same in the sync + // case as well, even though it's not strictly necessary, to keep the two + // code paths as similar as possible on both sides.) + // -1 - code is the encoding of a proxied EM_ASM, as a negative number + // (positive numbers are non-EM_ASM calls). + return _emscripten_proxy_to_main_thread_js.apply(null, [-1 - code, sync].concat(args)); + } +#endif + return ASM_CONSTS[code].apply(null, args); + }, + emscripten_asm_const_int_sync_on_main_thread__deps: ['$mainThreadEM_ASM'], + emscripten_asm_const_int_sync_on_main_thread__sig: 'iiii', + emscripten_asm_const_int_sync_on_main_thread: function(code, sigPtr, argbuf) { + return mainThreadEM_ASM(code, sigPtr, argbuf, 1); + }, + emscripten_asm_const_double_sync_on_main_thread: 'emscripten_asm_const_int_sync_on_main_thread', + emscripten_asm_const_async_on_main_thread__deps: ['$mainThreadEM_ASM'], + emscripten_asm_const_async_on_main_thread: function(code, sigPtr, argbuf) { + return mainThreadEM_ASM(code, sigPtr, argbuf, 0); + }, + #if !DECLARE_ASM_MODULE_EXPORTS // When DECLARE_ASM_MODULE_EXPORTS is not set we export native symbols // at runtime rather than statically in JS code. @@ -4186,12 +4229,6 @@ LibraryManager.library = { llvm_dbg_value: function() {}, llvm_debugtrap: function() {}, llvm_ctlz_i32: function() {}, - emscripten_asm_const: function() {}, - emscripten_asm_const_int: function() {}, - emscripten_asm_const_double: function() {}, - emscripten_asm_const_int_sync_on_main_thread: function() {}, - emscripten_asm_const_double_sync_on_main_thread: function() {}, - emscripten_asm_const_async_on_main_thread: function() {}, __handle_stack_overflow: function() { abort('stack overflow') diff --git a/tests/browser/test_em_asm_blocking.cpp b/tests/browser/test_em_asm_blocking.cpp index e275ce21561d..4f7382591121 100644 --- a/tests/browser/test_em_asm_blocking.cpp +++ b/tests/browser/test_em_asm_blocking.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,8 +8,15 @@ std::atomic ret; void foo() { int len = MAIN_THREAD_EM_ASM_INT({ var elem = document.getElementById('elem'); + window.almost_PI = 3.14159; return elem.innerText.length; }); + double almost_PI = MAIN_THREAD_EM_ASM_DOUBLE({ + // read a double from the main thread + return window.almost_PI; + }); + printf("almost PI: %f\n", almost_PI); + assert(fabs(almost_PI - 3.14159) < 0.001); atomic_store(&ret, len); }