Skip to content

Commit ed2e2dc

Browse files
authored
Simplify EM_ASM handling (#11972)
Emscripten counterpart to WebAssembly/binaryen#3044 , see background there, and WebAssembly/binaryen#3043 This basically gets rid of the special handling of EM_ASMs. Instead, they are just normal JS library methods like any other. (The one interesting thing in them, unchanged from before this PR, is that we need to read the varargs before doing any proxying, see the comment there for more details.)
1 parent 924d701 commit ed2e2dc

File tree

3 files changed

+55
-53
lines changed

3 files changed

+55
-53
lines changed

emscripten.py

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -493,14 +493,13 @@ def emscript(infile, outfile, memfile, temp_files, DEBUG):
493493

494494
report_missing_symbols(set([asmjs_mangle(f) for f in exports]), pre)
495495

496-
asm_consts, asm_const_funcs = create_asm_consts_wasm(forwarded_json, metadata)
496+
asm_consts = create_asm_consts_wasm(forwarded_json, metadata)
497497
em_js_funcs = create_em_js(forwarded_json, metadata)
498498
asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts]
499499
asm_const_map = 'var ASM_CONSTS = {\n ' + ', \n '.join(asm_const_pairs) + '\n};\n'
500500
pre = pre.replace(
501501
'// === Body ===',
502502
('// === Body ===\n\n' + asm_const_map +
503-
asstr('\n'.join(asm_const_funcs)) +
504503
'\n'.join(em_js_funcs) + '\n'))
505504
pre = apply_table(pre)
506505
outfile.write(pre)
@@ -585,6 +584,7 @@ def finalize_wasm(temp_files, infile, outfile, memfile, DEBUG):
585584
args.append('--pass-arg=legalize-js-interface-export-originals')
586585
if shared.Settings.DEBUG_LEVEL >= 3:
587586
args.append('--dwarf')
587+
args.append('--minimize-wasm-changes')
588588
stdout = building.run_binaryen_command('wasm-emscripten-finalize',
589589
infile=base_wasm,
590590
outfile=wasm,
@@ -606,7 +606,6 @@ def finalize_wasm(temp_files, infile, outfile, memfile, DEBUG):
606606

607607
def create_asm_consts_wasm(forwarded_json, metadata):
608608
asm_consts = {}
609-
all_sigs = []
610609
for k, v in metadata['asmConsts'].items():
611610
const, sigs, call_types = v
612611
const = asstr(const)
@@ -621,47 +620,9 @@ def create_asm_consts_wasm(forwarded_json, metadata):
621620
args.append('$' + str(i))
622621
const = 'function(' + ', '.join(args) + ') {' + const + '}'
623622
asm_consts[int(k)] = const
624-
for sig, call_type in zip(sigs, call_types):
625-
all_sigs.append((sig, call_type))
626-
627-
asm_const_funcs = []
628-
629-
for sig, call_type in set(all_sigs):
630-
const_name = '_emscripten_asm_const_' + call_type + sig
631-
forwarded_json['Functions']['libraryFunctions'][const_name] = 1
632-
633-
preamble = ''
634-
if shared.Settings.USE_PTHREADS:
635-
sync_proxy = call_type == 'sync_on_main_thread_'
636-
async_proxy = call_type == 'async_on_main_thread_'
637-
proxied = sync_proxy or async_proxy
638-
if proxied:
639-
# In proxied function calls, positive integers 1, 2, 3, ... denote pointers
640-
# to regular C compiled functions. Negative integers -1, -2, -3, ... denote
641-
# indices to EM_ASM() blocks, so remap the EM_ASM() indices from 0, 1, 2,
642-
# ... over to the negative integers starting at -1.
643-
preamble += ('\n if (ENVIRONMENT_IS_PTHREAD) { ' +
644-
proxy_debug_print(sync_proxy) +
645-
'return _emscripten_proxy_to_main_thread_js.apply(null, ' +
646-
'[-1 - code, ' + str(int(sync_proxy)) + '].concat(args)) }')
647-
648-
if shared.Settings.RELOCATABLE:
649-
preamble += '\n code -= %s;\n' % shared.Settings.GLOBAL_BASE
650-
651-
# EM_ASM functions are variadic, receiving the actual arguments as a buffer
652-
# in memory. the last parameter (argBuf) points to that data. We need to
653-
# alwayd un-variadify that, as in the async case this is a stack allocation
654-
# that LLVM made, which may go away before the main thread gets the message.
655-
# the readAsmConstArgs helper does so.
656-
asm_const_funcs.append(r'''
657-
function %s(code, sigPtr, argbuf) {
658-
var args = readAsmConstArgs(sigPtr, argbuf);
659-
%s
660-
return ASM_CONSTS[code].apply(null, args);
661-
}''' % (const_name, preamble))
662623
asm_consts = [(key, value) for key, value in asm_consts.items()]
663624
asm_consts.sort()
664-
return asm_consts, asm_const_funcs
625+
return asm_consts
665626

666627

667628
def create_em_js(forwarded_json, metadata):
@@ -815,13 +776,9 @@ def create_sending_wasm(invoke_funcs, forwarded_json, metadata):
815776
if shared.Settings.SAFE_HEAP:
816777
basic_funcs += ['segfault', 'alignfault']
817778

818-
em_asm_sigs = [zip(sigs, call_types) for _, sigs, call_types in metadata['asmConsts'].values()]
819-
# flatten em_asm_sigs
820-
em_asm_sigs = [sig for sigs in em_asm_sigs for sig in sigs]
821-
em_asm_funcs = ['_emscripten_asm_const_' + call_type + sig for sig, call_type in em_asm_sigs]
822779
em_js_funcs = list(metadata['emJsFuncs'].keys())
823780
declared_items = ['_' + item for item in metadata['declares']]
824-
send_items = set(basic_funcs + invoke_funcs + em_asm_funcs + em_js_funcs + declared_items)
781+
send_items = set(basic_funcs + invoke_funcs + em_js_funcs + declared_items)
825782

826783
def fix_import_name(g):
827784
if g.startswith('Math_'):

src/library.js

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3981,6 +3981,49 @@ LibraryManager.library = {
39813981
return readAsmConstArgsArray;
39823982
},
39833983

3984+
emscripten_asm_const_int__sig: 'iiii',
3985+
emscripten_asm_const_int: function(code, sigPtr, argbuf) {
3986+
#if RELOCATABLE
3987+
code -= {{{ GLOBAL_BASE }}};
3988+
#endif
3989+
var args = readAsmConstArgs(sigPtr, argbuf);
3990+
return ASM_CONSTS[code].apply(null, args);
3991+
},
3992+
emscripten_asm_const_double: 'emscripten_asm_const_int',
3993+
$mainThreadEM_ASM: function(code, sigPtr, argbuf, sync) {
3994+
#if RELOCATABLE
3995+
code -= {{{ GLOBAL_BASE }}};
3996+
#endif
3997+
var args = readAsmConstArgs(sigPtr, argbuf);
3998+
#if USE_PTHREADS
3999+
if (ENVIRONMENT_IS_PTHREAD) {
4000+
// EM_ASM functions are variadic, receiving the actual arguments as a buffer
4001+
// in memory. the last parameter (argBuf) points to that data. We need to
4002+
// always un-variadify that, *before proxying*, as in the async case this
4003+
// is a stack allocation that LLVM made, which may go away before the main
4004+
// thread gets the message. For that reason we handle proxying *after* the
4005+
// call to readAsmConstArgs, and therefore we do that manually here instead
4006+
// of using __proxy. (And dor simplicity, do the same in the sync
4007+
// case as well, even though it's not strictly necessary, to keep the two
4008+
// code paths as similar as possible on both sides.)
4009+
// -1 - code is the encoding of a proxied EM_ASM, as a negative number
4010+
// (positive numbers are non-EM_ASM calls).
4011+
return _emscripten_proxy_to_main_thread_js.apply(null, [-1 - code, sync].concat(args));
4012+
}
4013+
#endif
4014+
return ASM_CONSTS[code].apply(null, args);
4015+
},
4016+
emscripten_asm_const_int_sync_on_main_thread__deps: ['$mainThreadEM_ASM'],
4017+
emscripten_asm_const_int_sync_on_main_thread__sig: 'iiii',
4018+
emscripten_asm_const_int_sync_on_main_thread: function(code, sigPtr, argbuf) {
4019+
return mainThreadEM_ASM(code, sigPtr, argbuf, 1);
4020+
},
4021+
emscripten_asm_const_double_sync_on_main_thread: 'emscripten_asm_const_int_sync_on_main_thread',
4022+
emscripten_asm_const_async_on_main_thread__deps: ['$mainThreadEM_ASM'],
4023+
emscripten_asm_const_async_on_main_thread: function(code, sigPtr, argbuf) {
4024+
return mainThreadEM_ASM(code, sigPtr, argbuf, 0);
4025+
},
4026+
39844027
#if !DECLARE_ASM_MODULE_EXPORTS
39854028
// When DECLARE_ASM_MODULE_EXPORTS is not set we export native symbols
39864029
// at runtime rather than statically in JS code.
@@ -4186,12 +4229,6 @@ LibraryManager.library = {
41864229
llvm_dbg_value: function() {},
41874230
llvm_debugtrap: function() {},
41884231
llvm_ctlz_i32: function() {},
4189-
emscripten_asm_const: function() {},
4190-
emscripten_asm_const_int: function() {},
4191-
emscripten_asm_const_double: function() {},
4192-
emscripten_asm_const_int_sync_on_main_thread: function() {},
4193-
emscripten_asm_const_double_sync_on_main_thread: function() {},
4194-
emscripten_asm_const_async_on_main_thread: function() {},
41954232

41964233
__handle_stack_overflow: function() {
41974234
abort('stack overflow')

tests/browser/test_em_asm_blocking.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <assert.h>
12
#include <emscripten.h>
23
#include <stdio.h>
34
#include <thread>
@@ -7,8 +8,15 @@ std::atomic<int> ret;
78
void foo() {
89
int len = MAIN_THREAD_EM_ASM_INT({
910
var elem = document.getElementById('elem');
11+
window.almost_PI = 3.14159;
1012
return elem.innerText.length;
1113
});
14+
double almost_PI = MAIN_THREAD_EM_ASM_DOUBLE({
15+
// read a double from the main thread
16+
return window.almost_PI;
17+
});
18+
printf("almost PI: %f\n", almost_PI);
19+
assert(fabs(almost_PI - 3.14159) < 0.001);
1220
atomic_store(&ret, len);
1321
}
1422

0 commit comments

Comments
 (0)