diff --git a/system/include/emscripten/em_asm.h b/system/include/emscripten/em_asm.h index 26d457cb6b3eb..3128cea4311ce 100644 --- a/system/include/emscripten/em_asm.h +++ b/system/include/emscripten/em_asm.h @@ -175,14 +175,16 @@ void emscripten_asm_const_async_on_main_thread( // then wrap the whole code block inside parentheses (). See tests/core/test_em_asm_2.cpp // for example code snippets. +#define CODE_EXPR(code) ({ __attribute__((section("em_asm"), aligned(1))) static const char x[] = code; x; }) + // Runs the given JavaScript code on the calling thread (synchronously), and returns no value back. -#define EM_ASM(code, ...) ((void)emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))) +#define EM_ASM(code, ...) ((void)emscripten_asm_const_int(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__))) // Runs the given JavaScript code on the calling thread (synchronously), and returns an integer back. -#define EM_ASM_INT(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define EM_ASM_INT(code, ...) emscripten_asm_const_int(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) // Runs the given JavaScript code on the calling thread (synchronously), and returns a double back. -#define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) // Runs the given JavaScript code synchronously on the main browser thread, and returns no value back. // Call this function for example to access DOM elements in a pthread when building with -s USE_PTHREADS=1. @@ -193,29 +195,28 @@ void emscripten_asm_const_async_on_main_thread( // a return value back, consider using the function MAIN_THREAD_ASYNC_EM_ASM() instead, which will not block. // In single-threaded builds (including proxy-to-worker), MAIN_THREAD_EM_ASM*() // functions are direct aliases to the corresponding EM_ASM*() family of functions. -#define MAIN_THREAD_EM_ASM(code, ...) ((void)emscripten_asm_const_int_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))) +#define MAIN_THREAD_EM_ASM(code, ...) ((void)emscripten_asm_const_int_sync_on_main_thread(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__))) // Runs the given JavaScript code synchronously on the main browser thread, and returns an integer back. // The same considerations apply as with MAIN_THREAD_EM_ASM(). -#define MAIN_THREAD_EM_ASM_INT(code, ...) emscripten_asm_const_int_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define MAIN_THREAD_EM_ASM_INT(code, ...) emscripten_asm_const_int_sync_on_main_thread(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) // Runs the given JavaScript code synchronously on the main browser thread, and returns a double back. // The same considerations apply as with MAIN_THREAD_EM_ASM(). -#define MAIN_THREAD_EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define MAIN_THREAD_EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double_sync_on_main_thread(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) // Asynchronously dispatches the given JavaScript code to be run on the main browser thread. // If the calling thread is the main browser thread, then the specified JavaScript code is executed // synchronously. Otherwise an event will be queued on the main browser thread to execute the call -// later (think postMessage()), and this call will immediately return without waiting. Be sure to -// guard any accesses to shared memory on the heap inside the JavaScript code with appropriate locking. -#define MAIN_THREAD_ASYNC_EM_ASM(code, ...) ((void)emscripten_asm_const_async_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))) +// later (think postMessage()), and this call will immediately return without waiting. Be sure to guard any accesses to shared memory on the heap inside the JavaScript code with appropriate locking. +#define MAIN_THREAD_ASYNC_EM_ASM(code, ...) ((void)emscripten_asm_const_async_on_main_thread(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__))) // Old forms for compatibility, no need to use these. // Replace EM_ASM_, EM_ASM_ARGS and EM_ASM_INT_V with EM_ASM_INT, // and EM_ASM_DOUBLE_V with EM_ASM_DOUBLE. -#define EM_ASM_(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) -#define EM_ASM_ARGS(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)) -#define EM_ASM_INT_V(code) EM_ASM_INT(#code) -#define EM_ASM_DOUBLE_V(code) EM_ASM_DOUBLE(#code) +#define EM_ASM_(code, ...) emscripten_asm_const_int(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define EM_ASM_ARGS(code, ...) emscripten_asm_const_int(CODE_EXPR(#code) _EM_ASM_PREP_ARGS(__VA_ARGS__)) +#define EM_ASM_INT_V(code) EM_ASM_INT(code) +#define EM_ASM_DOUBLE_V(code) EM_ASM_DOUBLE(code) #endif // !defined(__cplusplus) && defined(__STRICT_ANSI__) diff --git a/system/include/emscripten/em_js.h b/system/include/emscripten/em_js.h index 02b26fd4b6adb..6a801ec2113c4 100644 --- a/system/include/emscripten/em_js.h +++ b/system/include/emscripten/em_js.h @@ -45,20 +45,20 @@ // We use <::> to separate the arguments from the function body because it isn't // valid anywhere in a C function declaration. -// Generated __em_js__-prefixed functions are read by either the JSBackend (for -// asm.js) or by Binaryen, and the string data is extracted into the Emscripten -// metadata dictionary under the "emJsFuncs" key. emJsFuncs itself is a -// dictionary where the keys are function names (not prefixed with __em_js__), -// and the values are the <::>-including description strings. +// Generated __em_js__-prefixed functions are read by binaryen, and the string +// data is extracted into the Emscripten metadata dictionary under the +// "emJsFuncs" key. emJsFuncs itself is a dictionary where the keys are function +// names (not prefixed with __em_js__), and the values are the <::>-including +// description strings. // emJsFuncs metadata is read in emscripten.py's create_em_js, which creates an // array of JS function strings to be included in the JS output. -#define EM_JS(ret, name, params, ...) \ - _EM_JS_CPP_BEGIN \ - extern ret name params EM_IMPORT(name); \ - __attribute__((used, visibility("default"))) \ - const char* __em_js__##name() { \ - return #params "<::>" #__VA_ARGS__; \ - } \ +#define EM_JS(ret, name, params, ...) \ + _EM_JS_CPP_BEGIN \ + extern ret name params EM_IMPORT(name); \ + __attribute__((used, visibility("default"))) const char* __em_js__##name() { \ + __attribute__((section("em_js"), aligned(1))) static const char s[] = #params "<::>" #__VA_ARGS__; \ + return s; \ + } \ _EM_JS_CPP_END diff --git a/tests/test_core.py b/tests/test_core.py index b0fede662f76f..7fd2738390f3a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1912,17 +1912,20 @@ def test_em_asm_arguments_side_effects(self): self.do_run_in_out_file_test('tests', 'core', 'test_em_asm_arguments_side_effects.cpp', force_c=True) @parameterized({ - 'normal': ([],), - 'linked': (['-s', 'MAIN_MODULE'],), + '': ([], False), + 'c': ([], True), + 'linked': (['-s', 'MAIN_MODULE'], False), + 'linked_c': (['-s', 'MAIN_MODULE'], True), }) - def test_em_js(self, args): + def test_em_js(self, args, force_c): if 'MAIN_MODULE' in args and not self.is_wasm(): self.skipTest('main module support for non-wasm') if '-fsanitize=address' in self.emcc_args: self.skipTest('no dynamic library support in asan yet') self.emcc_args += args + ['-s', 'EXPORTED_FUNCTIONS=["_main","_malloc"]'] - self.do_run_in_out_file_test('tests', 'core', 'test_em_js.cpp') - self.do_run_in_out_file_test('tests', 'core', 'test_em_js.cpp', force_c=True) + + self.do_run_in_out_file_test('tests', 'core', 'test_em_js.cpp', force_c=force_c) + self.assertContained("no args returning int", open('test_em_js.js').read()) def test_runtime_stacksave(self): self.do_runf(path_from_root('tests', 'core', 'test_runtime_stacksave.c'), 'success') diff --git a/tests/test_other.py b/tests/test_other.py index 329ec0a12cddd..c2abe67aca713 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7018,7 +7018,7 @@ def test_export_aliasee(self): self.run_process(cmd) # build main module - args = ['-s', 'EXPORTED_FUNCTIONS=["_main", "_foo"]', '-s', 'MAIN_MODULE=2', '-s', 'EXIT_RUNTIME', '-lnodefs.js'] + args = ['-g', '-s', 'EXPORTED_FUNCTIONS=["_main", "_foo"]', '-s', 'MAIN_MODULE=2', '-s', 'EXIT_RUNTIME', '-lnodefs.js'] cmd = [EMCC, path_from_root('tests', 'other', 'alias', 'main.c'), '-o', 'main.js'] + args print(' '.join(cmd)) self.run_process(cmd) @@ -7536,7 +7536,7 @@ def test_js_optimizer_parse_error(self): var ASM_CONSTS = [function() { var x = !<->5.; }]; ^ ''', ''' - 1024: function() {var x = !<->5.;} + 1025: function() {var x = !<->5.;} ^ '''), stderr) diff --git a/tools/building.py b/tools/building.py index 38c26e4502127..99869f5c72fb5 100644 --- a/tools/building.py +++ b/tools/building.py @@ -570,7 +570,11 @@ def lld_flags_for_executable(external_symbol_list): cmd.append('--growable-table') if not Settings.SIDE_MODULE: + # Export these two section start symbols so that we can extact the string + # data that they contain. cmd += [ + '--export', '__start_em_asm', + '--export', '__stop_em_asm', '-z', 'stack-size=%s' % Settings.TOTAL_STACK, '--initial-memory=%d' % Settings.INITIAL_MEMORY, ]