From 86c18212b16bad46e85fa0c44090a6731c0ef8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 26 Jan 2020 17:55:07 +0200 Subject: [PATCH 01/17] More tests working with MINIMAL_RUNTIME in Wasm backend. ASan support to MINIMAL_RUNTIME. --- emcc.py | 3 +++ src/library_syscall.js | 4 ++++ tests/test_core.py | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/emcc.py b/emcc.py index 4ba8a6b9c3583..4d75558ecb9f8 100755 --- a/emcc.py +++ b/emcc.py @@ -1723,6 +1723,9 @@ def is_supported_link_flag(f): if shared.Settings.LINKABLE: exit_with_error('LSan does not support dynamic linking') + if shared.Settings.MINIMAL_RUNTIME: + exit_with_error('MINIMAL_RUNTIME is currently not compatible LSan') + if 'address' in sanitize: shared.Settings.USE_ASAN = 1 diff --git a/src/library_syscall.js b/src/library_syscall.js index ba8442ae44dc0..d3b1a419688e4 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -227,9 +227,13 @@ var SyscallsLibrary = { _emscripten_syscall_mmap2__deps: ['memalign', 'memset', '$SYSCALLS', #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM '$FS', +#endif +#if MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have a global PAGE_SIZE runtime variable. + 'getpagesize' #endif ], _emscripten_syscall_mmap2: function(addr, len, prot, flags, fd, off) { +#endif off <<= 12; // undo pgoffset var ptr; var allocated = false; diff --git a/tests/test_core.py b/tests/test_core.py index 2e8b667d449f2..131389ab9455f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5164,6 +5164,7 @@ def test_utf8_invalid(self): self.do_run(open(path_from_root('tests', 'utf8_invalid.cpp')).read(), 'OK.') # Test that invalid character in UTF8 does not cause decoding to crash. + @no_lsan('TODO: LSan with MINIMAL_RUNTIME') @no_emterpreter def test_minimal_runtime_utf8_invalid(self): self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8']) @@ -8432,6 +8433,7 @@ def test_no_declare_asm_module_exports(self): # Tests that building with -s DECLARE_ASM_MODULE_EXPORTS=0 works @no_emterpreter + @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_no_declare_asm_module_exports(self): self.set_setting('DECLARE_ASM_MODULE_EXPORTS', 0) self.set_setting('WASM_ASYNC_COMPILATION', 0) @@ -8468,6 +8470,7 @@ def test_minimal_runtime_hello_printf(self, args): # Tests that -s MINIMAL_RUNTIME=1 works well with SAFE_HEAP @no_emterpreter + @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_safe_heap(self): self.emcc_args = ['-s', 'MINIMAL_RUNTIME=1', '-s', 'SAFE_HEAP=1'] self.maybe_closure() @@ -8475,6 +8478,7 @@ def test_minimal_runtime_safe_heap(self): # Tests global initializer with -s MINIMAL_RUNTIME=1 @no_emterpreter + @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_global_initializer(self): self.set_setting('MINIMAL_RUNTIME', 1) self.maybe_closure() @@ -8777,6 +8781,7 @@ def test_emscripten_get_exported_function(self): self.do_run_in_out_file_test('tests', 'core', 'test_get_exported_function') # Tests the emscripten_get_exported_function() API. + @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_emscripten_get_exported_function(self): # Could also test with -s ALLOW_TABLE_GROWTH=1 self.set_setting('RESERVED_FUNCTION_POINTERS', 2) From c6750f31a2a6cba9fe755e95574633ecd8931711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 26 Jan 2020 17:57:06 +0200 Subject: [PATCH 02/17] LSan works too --- emcc.py | 3 --- tests/test_core.py | 5 ----- 2 files changed, 8 deletions(-) diff --git a/emcc.py b/emcc.py index 4d75558ecb9f8..4ba8a6b9c3583 100755 --- a/emcc.py +++ b/emcc.py @@ -1723,9 +1723,6 @@ def is_supported_link_flag(f): if shared.Settings.LINKABLE: exit_with_error('LSan does not support dynamic linking') - if shared.Settings.MINIMAL_RUNTIME: - exit_with_error('MINIMAL_RUNTIME is currently not compatible LSan') - if 'address' in sanitize: shared.Settings.USE_ASAN = 1 diff --git a/tests/test_core.py b/tests/test_core.py index 131389ab9455f..2e8b667d449f2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5164,7 +5164,6 @@ def test_utf8_invalid(self): self.do_run(open(path_from_root('tests', 'utf8_invalid.cpp')).read(), 'OK.') # Test that invalid character in UTF8 does not cause decoding to crash. - @no_lsan('TODO: LSan with MINIMAL_RUNTIME') @no_emterpreter def test_minimal_runtime_utf8_invalid(self): self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8']) @@ -8433,7 +8432,6 @@ def test_no_declare_asm_module_exports(self): # Tests that building with -s DECLARE_ASM_MODULE_EXPORTS=0 works @no_emterpreter - @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_no_declare_asm_module_exports(self): self.set_setting('DECLARE_ASM_MODULE_EXPORTS', 0) self.set_setting('WASM_ASYNC_COMPILATION', 0) @@ -8470,7 +8468,6 @@ def test_minimal_runtime_hello_printf(self, args): # Tests that -s MINIMAL_RUNTIME=1 works well with SAFE_HEAP @no_emterpreter - @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_safe_heap(self): self.emcc_args = ['-s', 'MINIMAL_RUNTIME=1', '-s', 'SAFE_HEAP=1'] self.maybe_closure() @@ -8478,7 +8475,6 @@ def test_minimal_runtime_safe_heap(self): # Tests global initializer with -s MINIMAL_RUNTIME=1 @no_emterpreter - @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_global_initializer(self): self.set_setting('MINIMAL_RUNTIME', 1) self.maybe_closure() @@ -8781,7 +8777,6 @@ def test_emscripten_get_exported_function(self): self.do_run_in_out_file_test('tests', 'core', 'test_get_exported_function') # Tests the emscripten_get_exported_function() API. - @no_lsan('TODO: LSan with MINIMAL_RUNTIME') def test_minimal_runtime_emscripten_get_exported_function(self): # Could also test with -s ALLOW_TABLE_GROWTH=1 self.set_setting('RESERVED_FUNCTION_POINTERS', 2) From 2d41a68492dce0f135f021cf6677344839464321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 28 Jan 2020 11:49:15 +0200 Subject: [PATCH 03/17] Enable more of the core test suite to build on MINIMAL_RUNTIME. --- src/deps_info.json | 14 ++++++------- src/library.js | 40 +++++++++++++++++++++++++++++-------- src/library_nodefs.js | 4 ++++ src/library_pthread_stub.js | 16 ++++----------- src/library_strings.js | 5 ++++- src/library_syscall.js | 3 +++ src/library_wasi.js | 10 +++++++--- src/modules.js | 32 ++++++++++++++++------------- src/settings.js | 2 +- 9 files changed, 80 insertions(+), 46 deletions(-) diff --git a/src/deps_info.json b/src/deps_info.json index 8914d7a5dbd4f..7103bbe808c50 100644 --- a/src/deps_info.json +++ b/src/deps_info.json @@ -80,13 +80,13 @@ "sleep": ["usleep"], "recv": ["htons"], "send": ["htons"], - "ctime": ["_get_tzname", "_get_daylight", "_get_timezone"], - "ctime_r": ["_get_tzname", "_get_daylight", "_get_timezone"], - "localtime": ["_get_tzname", "_get_daylight", "_get_timezone"], - "localtime_r": ["_get_tzname", "_get_daylight", "_get_timezone"], - "mktime": ["_get_tzname", "_get_daylight", "_get_timezone"], - "timegm": ["_get_tzname", "_get_daylight", "_get_timezone"], - "tzset": ["_get_tzname", "_get_daylight", "_get_timezone"], + "ctime": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "ctime_r": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "localtime": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "localtime_r": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "mktime": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "timegm": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], + "tzset": ["_get_tzname", "_get_daylight", "_get_timezone", "malloc"], "emscripten_set_canvas_element_size_calling_thread": ["emscripten_async_queue_on_thread_"], "emscripten_webgl_destroy_context": ["emscripten_webgl_make_context_current", "emscripten_webgl_get_current_context"], "emscripten_webgl_create_context": ["malloc", "free"], diff --git a/src/library.js b/src/library.js index 005ce6f41cfb8..6af32cc831f9e 100644 --- a/src/library.js +++ b/src/library.js @@ -746,7 +746,7 @@ LibraryManager.library = { // to limitations in the system libraries (we can't easily add a global // ctor to create the environment without it always being linked in with // libc). - __buildEnvironment__deps: ['$ENV'], + __buildEnvironment__deps: ['$ENV', '_get_executable_name'], __buildEnvironment: function(environ) { // WARNING: Arbitrary limit! var MAX_ENV_VALUES = 64; @@ -765,7 +765,7 @@ LibraryManager.library = { ENV['HOME'] = '/home/web_user'; // Browser language detection #8751 ENV['LANG'] = ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8'; - ENV['_'] = thisProgram; + ENV['_'] = __get_executable_name(); // Allocate memory. #if !MINIMAL_RUNTIME // TODO: environment support in MINIMAL_RUNTIME poolPtr = getMemory(TOTAL_ENV_SIZE); @@ -1844,12 +1844,12 @@ LibraryManager.library = { } }, - dladdr__deps: ['$stringToNewUTF8'], + dladdr__deps: ['$stringToNewUTF8', '_get_executable_name'], dladdr__proxy: 'sync', dladdr__sig: 'iii', dladdr: function(addr, info) { // report all function pointers as coming from this program itself XXX not really correct in any way - var fname = stringToNewUTF8(thisProgram || './this.program'); // XXX leak + var fname = __get_executable_name(); // XXX leak {{{ makeSetValue('info', 0, 'fname', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE, '0', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE*2, '0', 'i32') }}}; @@ -2068,6 +2068,9 @@ LibraryManager.library = { // Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm) tzset__proxy: 'sync', tzset__sig: 'v', +#if MINIMAL_RUNTIME + tzset__deps: ['$allocateUTF8'], +#endif tzset: function() { // TODO: Use (malleable) environment variables instead of system settings. if (_tzset.called) return; @@ -2091,8 +2094,8 @@ LibraryManager.library = { }; var winterName = extractZone(winter); var summerName = extractZone(summer); - var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL); - var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL); + var winterNamePtr = allocateUTF8(winterName); + var summerNamePtr = allocateUTF8(summerName); if (summer.getTimezoneOffset() < winter.getTimezoneOffset()) { // Northern hemisphere {{{ makeSetValue('__get_tzname()', '0', 'winterNamePtr', 'i32') }}}; @@ -2158,7 +2161,11 @@ LibraryManager.library = { // Note: this is not used in STANDALONE_WASM mode, because it is more // compact to do it in JS. - strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'], + strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP' +#if MINIMAL_RUNTIME + , '$intArrayFromString' +#endif + ], strftime: function(s, maxsize, format, tm) { // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr); // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html @@ -2481,7 +2488,11 @@ LibraryManager.library = { return _strftime(s, maxsize, format, tm); // no locale support yet }, - strptime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'], + strptime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP' +#if MINIMAL_RUNTIME + , '$intArrayFromString' +#endif + ], strptime: function(buf, format, tm) { // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html @@ -5149,6 +5160,19 @@ LibraryManager.library = { __handle_stack_overflow: function() { abort('stack overflow') }, + + _get_executable_name: function() { +#if MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have a global runtime variable thisProgram +#if ENVIRONMENT_MAY_BE_NODE + if (ENVIRONMENT_IS_NODE && process['argv'].length > 1) { + return process['argv'][1].replace(/\\/g, '/'); + } +#endif + return "./this.program"; +#else + return thisProgram || './this.program'; +#endif + }, }; function autoAddDeps(object, name) { diff --git a/src/library_nodefs.js b/src/library_nodefs.js index 780c15ecf3053..415da896a49f1 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -34,11 +34,15 @@ mergeInto(LibraryManager.library, { }, convertNodeCode: function(e) { var code = e.code; +#if ASSERTIONS assert(code in ERRNO_CODES); +#endif return ERRNO_CODES[code]; }, mount: function (mount) { +#if ASSERTIONS assert(ENVIRONMENT_IS_NODE); +#endif return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0); }, createNode: function (parent, name, mode, dev) { diff --git a/src/library_pthread_stub.js b/src/library_pthread_stub.js index 3d47b3c404d24..0a3749d0edcd4 100644 --- a/src/library_pthread_stub.js +++ b/src/library_pthread_stub.js @@ -163,23 +163,15 @@ var LibraryPThreadStub = { emscripten_main_browser_thread_id: function() { return _pthread_self(); }, // When pthreads is not enabled, we can't use the Atomics futex api to do proper sleeps, so simulate a busy spin wait loop instead. + usleep__deps: ['emscripten_get_now'], usleep: function(useconds) { // int usleep(useconds_t useconds); // http://pubs.opengroup.org/onlinepubs/000095399/functions/usleep.html // We're single-threaded, so use a busy loop. Super-ugly. - var msec = useconds / 1000; - if ((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self['performance'] && self['performance']['now']) { - var start = self['performance']['now'](); - while (self['performance']['now']() - start < msec) { - // Do nothing. - } - } else { - var start = Date.now(); - while (Date.now() - start < msec) { - // Do nothing. - } + var start = _emscripten_get_now(); + while (_emscripten_get_now() - start < useconds / 1000) { + // Do nothing. } - return 0; }, nanosleep__deps: ['usleep', '__setErrNo'], diff --git a/src/library_strings.js b/src/library_strings.js index 6fa0580cf0c1d..277946107901c 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -1,6 +1,7 @@ #if MINIMAL_RUNTIME #include "runtime_strings_extra.js" +#include "arrayUtils.js" mergeInto(LibraryManager.library, { $AsciiToString: AsciiToString, @@ -15,7 +16,9 @@ mergeInto(LibraryManager.library, { $allocateUTF8OnStack: allocateUTF8OnStack, $writeStringToMemory: writeStringToMemory, $writeArrayToMemory: writeArrayToMemory, - $writeAsciiToMemory: writeAsciiToMemory + $writeAsciiToMemory: writeAsciiToMemory, + $intArrayFromString: intArrayFromString, + $intArrayToString: intArrayToString }); #endif diff --git a/src/library_syscall.js b/src/library_syscall.js index d3b1a419688e4..cd46418ca1396 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -743,6 +743,9 @@ var SyscallsLibrary = { __syscall121: function(which, varargs) { // setdomainname return -{{{ cDefine('EPERM') }}}; }, +#if MINIMAL_RUNTIME + __syscall122__deps: ['$writeAsciiToMemory'], +#endif __syscall122: function(which, varargs) { // uname var buf = SYSCALLS.get(); if (!buf) return -{{{ cDefine('EFAULT') }}} diff --git a/src/library_wasi.js b/src/library_wasi.js index 70632d115e2fb..6084d841ca7dd 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -11,7 +11,7 @@ var WasiLibrary = { return _exit(code); }, - emscripten_get_environ__deps: ['$ENV'], + emscripten_get_environ__deps: ['$ENV', '_get_executable_name'], emscripten_get_environ: function() { if (!_emscripten_get_environ.strings) { // Default values. @@ -23,7 +23,7 @@ var WasiLibrary = { 'HOME': '/home/web_user', // Browser language detection #8751 'LANG': ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8', - '_': thisProgram + '_': __get_executable_name() }; // Apply the user-provided values, if any. for (var x in ENV) { @@ -50,7 +50,11 @@ var WasiLibrary = { return 0; }, - environ_get__deps: ['emscripten_get_environ'], + environ_get__deps: ['emscripten_get_environ' +#if MINIMAL_RUNTIME + , '$writeAsciiToMemory' +#endif + ], environ_get: function(__environ, environ_buf) { var strings = _emscripten_get_environ(); var bufSize = 0; diff --git a/src/modules.js b/src/modules.js index 964746c1e4a00..129ce4db4fc83 100644 --- a/src/modules.js +++ b/src/modules.js @@ -376,21 +376,11 @@ function exportRuntime() { 'getValue', 'allocate', 'getMemory', - 'AsciiToString', - 'stringToAscii', 'UTF8ArrayToString', 'UTF8ToString', 'stringToUTF8Array', 'stringToUTF8', 'lengthBytesUTF8', - 'UTF16ToString', - 'stringToUTF16', - 'lengthBytesUTF16', - 'UTF32ToString', - 'stringToUTF32', - 'lengthBytesUTF32', - 'allocateUTF8', - 'allocateUTF8OnStack', 'stackTrace', 'addOnPreRun', 'addOnInit', @@ -436,10 +426,24 @@ function exportRuntime() { ]; if (!MINIMAL_RUNTIME) { - runtimeElements.push('warnOnce'); - runtimeElements.push('stackSave'); - runtimeElements.push('stackRestore'); - runtimeElements.push('stackAlloc'); + // MINIMAL_RUNTIME has moved these functions to library_strings.js + runtimeElements = runtimeElements.concat([ + 'warnOnce', + 'stackSave', + 'stackRestore', + 'stackAlloc', + 'AsciiToString', + 'stringToAscii', + 'UTF16ToString', + 'stringToUTF16', + 'lengthBytesUTF16', + 'UTF32ToString', + 'stringToUTF32', + 'lengthBytesUTF32', + 'allocateUTF8', + 'allocateUTF8OnStack' + ]); + if (USE_PTHREADS) { runtimeElements.push('establishStackSpace'); } diff --git a/src/settings.js b/src/settings.js index d09f24b31f9fd..01cacd4d81a45 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1626,7 +1626,7 @@ var SUPPORT_ERRNO = 1; // opts are quite hacky, and work around limitations in Closure and other parts // of the build system, so they may not work in all generated programs (But can // be useful for really small programs) -var MINIMAL_RUNTIME = 0; +var MINIMAL_RUNTIME = 1; // If set to 1, MINIMAL_RUNTIME will utilize streaming WebAssembly compilation, // where WebAssembly module is compiled already while it is being downloaded. From 91e900841de79151a8c1c704bcc654cc5710a2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 28 Jan 2020 19:58:53 +0200 Subject: [PATCH 04/17] More core test suite working in MINIMAL_RUNTIME. --- emcc.py | 5 +++-- src/library.js | 4 ++-- src/library_html5.js | 2 +- src/library_syscall.js | 7 +++---- src/postamble_minimal.js | 16 ++++++++++++++++ src/preamble_minimal.js | 25 +++++++++++++++++++++++++ tests/test_core.py | 32 +++++++++++++++++++++++++++----- tests/utf32.cpp | 16 ++++++++-------- tests/utf8.cpp | 26 +++++++++++++------------- 9 files changed, 98 insertions(+), 35 deletions(-) diff --git a/emcc.py b/emcc.py index 4ba8a6b9c3583..a9c5c0fc44023 100755 --- a/emcc.py +++ b/emcc.py @@ -1250,8 +1250,9 @@ def is_supported_link_flag(f): link_flags = [f for f in link_flags if is_supported_link_flag(f[1])] if shared.Settings.MINIMAL_RUNTIME: - # Remove the default exported functions 'memcpy', 'memset', 'malloc', 'free', etc. - those should only be linked in if used - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = [] + # Remove the default exported functions 'malloc', 'free' - those should only be linked in if used + for to_remove in ['malloc', 'free']: + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) if shared.Settings.STACK_OVERFLOW_CHECK: if shared.Settings.MINIMAL_RUNTIME: diff --git a/src/library.js b/src/library.js index 6af32cc831f9e..f2f8494c65ab4 100644 --- a/src/library.js +++ b/src/library.js @@ -703,7 +703,7 @@ LibraryManager.library = { _exit(-1234); }, -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !EXIT_RUNTIME atexit: function(){}, __cxa_atexit: function(){}, __cxa_thread_atexit: function(){}, @@ -2163,7 +2163,7 @@ LibraryManager.library = { // compact to do it in JS. strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP' #if MINIMAL_RUNTIME - , '$intArrayFromString' + , '$intArrayFromString', '$writeArrayToMemory' #endif ], strftime: function(s, maxsize, format, tm) { diff --git a/src/library_html5.js b/src/library_html5.js index dfe96d7378c59..5ff82e72e9612 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -41,7 +41,7 @@ var LibraryJSEvents = { #endif }, -#if !MINIMAL_RUNTIME // In minimal runtime, there is no concept of the page running vs being closed, and hence __ATEXIT__ is not present +#if !MINIMAL_RUNTIME || EXIT_RUNTIME // In minimal runtime, there is no concept of the page running vs being closed, and hence __ATEXIT__ is not present registerRemoveEventListeners: function() { if (!JSEvents.removeEventListenersRegistered) { __ATEXIT__.push(JSEvents.removeAllEventListeners); diff --git a/src/library_syscall.js b/src/library_syscall.js index cd46418ca1396..4348d4a4adfcf 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -1364,17 +1364,16 @@ var SyscallsLibrary = { // This is the set of syscalls that use the FS etc. APIs. The rest is in // library_wasi.js. -#if SYSCALLS_REQUIRE_FILESYSTEM == 0 +#if SYSCALLS_REQUIRE_FILESYSTEM == 0 && (!MINIMAL_RUNTIME || EXIT_RUNTIME) $flush_NO_FILESYSTEM: function() { // flush anything remaining in the buffers during shutdown - var fflush = Module["_fflush"]; - if (fflush) fflush(0); + if (typeof _fflush !== 'undefined') _fflush(0); var buffers = SYSCALLS.buffers; if (buffers[1].length) SYSCALLS.printChar(1, {{{ charCode("\n") }}}); if (buffers[2].length) SYSCALLS.printChar(2, {{{ charCode("\n") }}}); }, fd_write__deps: ['$flush_NO_FILESYSTEM'], -#if EXIT_RUNTIME == 1 && !MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have __ATEXIT__ (so it does not get flushed stdout at program exit - programs in MINIMAL_RUNTIME do not have a concept of exiting) +#if EXIT_RUNTIME == 1 fd_write__postset: '__ATEXIT__.push(flush_NO_FILESYSTEM);', #endif #endif diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index c21811c3fa02e..049c9f55b493b 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -14,6 +14,22 @@ function run() { var ret = _proxy_main(); #else var ret = _main(); + +#if EXIT_RUNTIME + callRuntimeCallbacks(__ATEXIT__); + {{{ getQuoted('ATEXITS') }}} +#endif + +#if FILESYSTEM && (ASSERTIONS || IN_TEST_HARNESS) + // fflush() filesystem stdio for test harness. For production use, instead print full lines to avoid this kind of + // lazy behavior. + _fflush(); +#endif + +#if ASSERTIONS + runtimeExited = true; +#endif + #endif #if STACK_OVERFLOW_CHECK diff --git a/src/preamble_minimal.js b/src/preamble_minimal.js index 2420615b652fd..2b2f5b4ac53df 100644 --- a/src/preamble_minimal.js +++ b/src/preamble_minimal.js @@ -185,6 +185,31 @@ var wasmOffsetConverter; #include "wasm_offset_converter.js" #endif +#if EXIT_RUNTIME + +function callRuntimeCallbacks(callbacks) { + while(callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == 'function') { + callback(); + continue; + } + var func = callback.func; + if (typeof func === 'number') { + if (callback.arg === undefined) { + dynCall_v(func); + } else { + dynCall_vi(func, callback.arg); + } + } else { + func(callback.arg === undefined ? null : callback.arg); + } + } +} + +var __ATEXIT__ = []; // functions called during shutdown +#endif + #if ASSERTIONS var runtimeInitialized = false; diff --git a/tests/test_core.py b/tests/test_core.py index 2e8b667d449f2..4a335febb1102 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -233,6 +233,20 @@ def decorated(self, *args, **kwargs): return decorator +def no_minimal_runtime(note): + assert not callable(note) + + def decorator(f): + assert callable(f) + + @wraps(f) + def decorated(self, *args, **kwargs): + if 'MINIMAL_RUNTIME=1' in self.emcc_args or self.get_setting('MINIMAL_RUNTIME'): + self.skipTest(note) + f(self, *args, **kwargs) + return decorated + return decorator + class TestCoreBase(RunnerCore): def is_wasm2js(self): return self.is_wasm_backend() and not self.get_setting('WASM') @@ -1971,7 +1985,7 @@ def test_em_asm_arguments_side_effects(self): def test_em_js(self, args): if 'MAIN_MODULE' in args and self.get_setting('WASM') == 0: self.skipTest('main module support for non-wasm') - self.emcc_args += args + self.emcc_args += args + ['-s', 'EXPORTED_FUNCTIONS=["_main","_malloc"]'] self.do_run_in_out_file_test('tests', 'core', 'test_em_js') self.do_run_in_out_file_test('tests', 'core', 'test_em_js', force_c=True) @@ -5133,20 +5147,27 @@ def test_utime(self): src = open(path_from_root('tests', 'utime', 'test_utime.c')).read() self.do_run(src, 'success', force_c=True) + @no_minimal_runtime('MINIMAL_RUNTIME does not have getValue() and setValue() (TODO add it to a JS library function to get it in)') def test_utf(self): self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well - self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_malloc']) + self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_malloc',]) self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['getValue', 'setValue', 'UTF8ToString', 'stringToUTF8']) self.do_run_in_out_file_test('tests', 'core', 'test_utf') def test_utf32(self): - self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32']) + if self.get_setting('MINIMAL_RUNTIME'): + self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$UTF32ToString', '$stringToUTF32', '$lengthBytesUTF32']) + else: + self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32']) self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.') self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.', args=['-fshort-wchar']) def test_utf8(self): - self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', - ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) + if self.get_setting('MINIMAL_RUNTIME'): + self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$AsciiToString', '$stringToAscii', '$writeAsciiToMemory']) + else: + self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', + ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) self.emcc_args += ['-std=c++11'] self.do_run(open(path_from_root('tests', 'utf8.cpp')).read(), 'OK.') @@ -6588,6 +6609,7 @@ def test_EXTRA_EXPORTED_RUNTIME_METHODS(self): self.do_run_in_out_file_test('tests', 'core', 'EXTRA_EXPORTED_RUNTIME_METHODS') @no_fastcomp('fails mysteriously on fastcomp (dynCall_viji is not defined); ignored, because fastcomp is deprecated') + @no_minimal_runtime('MINIMAL_RUNTIME does not blindly export all symbols to Module to save code size') def test_dyncall_specific(self): emcc_args = self.emcc_args[:] for which, exported_runtime_methods in [ diff --git a/tests/utf32.cpp b/tests/utf32.cpp index 64674bea03ef6..6acd298a1e529 100644 --- a/tests/utf32.cpp +++ b/tests/utf32.cpp @@ -22,9 +22,9 @@ int main() { utf32 *memory = new utf32[wstr.length()+1]; EM_ASM({ - var str = Module.UTF32ToString($0); + var str = UTF32ToString($0); out(str); - var numBytesWritten = Module.stringToUTF32(str, $1, $2); + var numBytesWritten = stringToUTF32(str, $1, $2); if (numBytesWritten != 23*4) throw 'stringToUTF32 wrote an invalid length ' + numBytesWritten; }, wstr.c_str(), memory, (wstr.length()+1)*sizeof(utf32)); @@ -37,9 +37,9 @@ int main() { } EM_ASM({ - var str = Module.UTF32ToString($0); + var str = UTF32ToString($0); out(str); - var numBytesWritten = Module.stringToUTF32(str, $1, $2); + var numBytesWritten = stringToUTF32(str, $1, $2); if (numBytesWritten != 5*4) throw 'stringToUTF32 wrote an invalid length ' + numBytesWritten; }, wstr.c_str(), memory, 6*sizeof(utf32)); assert(memory[5] == 0); @@ -49,9 +49,9 @@ int main() { utf16 *memory = new utf16[2*wstr.length()+1]; EM_ASM({ - var str = Module.UTF16ToString($0); + var str = UTF16ToString($0); out(str); - var numBytesWritten = Module.stringToUTF16(str, $1, $2); + var numBytesWritten = stringToUTF16(str, $1, $2); if (numBytesWritten != 25*2) throw 'stringToUTF16 wrote an invalid length ' + numBytesWritten; }, wstr.c_str(), memory, (2*wstr.length()+1)*sizeof(utf16)); @@ -64,9 +64,9 @@ int main() { } EM_ASM({ - var str = Module.UTF16ToString($0); + var str = UTF16ToString($0); out(str); - var numBytesWritten = Module.stringToUTF16(str, $1, $2); + var numBytesWritten = stringToUTF16(str, $1, $2); if (numBytesWritten != 5*2) throw 'stringToUTF16 wrote an invalid length ' + numBytesWritten; }, wstr.c_str(), memory, 6*sizeof(utf16)); assert(memory[5] == 0); diff --git a/tests/utf8.cpp b/tests/utf8.cpp index ea9335f48f369..fabb1412c6028 100644 --- a/tests/utf8.cpp +++ b/tests/utf8.cpp @@ -14,24 +14,24 @@ int main() { const char latin1String[] = "\x26\xA0\xF7"; EM_ASM({ - var str = Module.AsciiToString($0); + var str = AsciiToString($0); assert(str === "\\x26\\xA0\\xF7"); }, latin1String); const char asciiString[] = "Hello world!"; char asciiString2[128] = {}; EM_ASM({ - var str = Module.AsciiToString($0); + var str = AsciiToString($0); out(str); - Module.stringToAscii(str, $1); + stringToAscii(str, $1); }, asciiString, asciiString2); assert(!strcmp(asciiString, asciiString2)); char asciiString3[128] = {}; EM_ASM({ - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); out(str); - var numBytesWritten = Module.stringToUTF8(str, $1, $2); + var numBytesWritten = stringToUTF8(str, $1, $2); if (numBytesWritten != 12) throw 'stringToUTF8 wrote an invalid length ' + numBytesWritten; }, asciiString, asciiString3, 128); assert(!strcmp(asciiString, asciiString3)); @@ -39,9 +39,9 @@ int main() { const char utf8String[] = u8"Hyv\u00E4\u00E4 p\u00E4iv\u00E4\u00E4! T\u00F6\u00F6\u00F6\u00F6t! abc\u2603\u20AC\U0002007C123 --- abc\u2603\u20AC\U0002007C123."; // U+2603 is snowman, U+20AC is the Euro sign, U+2007C is a Chinese Han character that looks like three raindrops. char utf8String2[128] = {}; EM_ASM({ - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); out(str); - var numBytesWritten = Module.stringToUTF8(str, $1, $2); + var numBytesWritten = stringToUTF8(str, $1, $2); if (numBytesWritten != 69) throw 'stringToUTF8 wrote an invalid length ' + numBytesWritten; }, utf8String, utf8String2, 128); assert(strlen(utf8String) == strlen(utf8String2)); @@ -52,18 +52,18 @@ int main() { // Test that text gets properly cut off if output buffer is too small. EM_ASM({ - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); out(str); - var numBytesWritten = Module.stringToUTF8(str, $1, $2); + var numBytesWritten = stringToUTF8(str, $1, $2); if (numBytesWritten != 9) throw 'stringToUTF8 wrote an invalid length ' + numBytesWritten; }, utf8String, utf8String2, 10); assert(strlen(utf8String2) == 9); // Zero-length string. EM_ASM({ - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); out(str); - var numBytesWritten = Module.stringToUTF8(str, $1, $2); + var numBytesWritten = stringToUTF8(str, $1, $2); if (numBytesWritten != 0) throw 'stringToUTF8 wrote an invalid length ' + numBytesWritten; }, utf8String, utf8String2, 1); assert(utf8String2[0] == 0); @@ -71,9 +71,9 @@ int main() { // No bytes output. utf8String2[0] = 'X'; EM_ASM({ - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); out(str); - var numBytesWritten = Module.stringToUTF8(str, $1, $2); + var numBytesWritten = stringToUTF8(str, $1, $2); if (numBytesWritten != 0) throw 'stringToUTF8 wrote an invalid length ' + numBytesWritten; }, utf8String, utf8String2, 0); assert(utf8String2[0] == 'X'); From 77a59a2b65cb406b3cb0a54fa8a0c1c7886a52b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 30 Jan 2020 18:50:14 +0200 Subject: [PATCH 05/17] Add missing printf deps in MINIMAL_RUNTIME --- src/library_formatString.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/library_formatString.js b/src/library_formatString.js index bc6bb387a6640..09082d2bc4edb 100644 --- a/src/library_formatString.js +++ b/src/library_formatString.js @@ -418,7 +418,11 @@ mergeInto(LibraryManager.library, { }, // printf/puts implementations for when musl is not pulled in - very partial. useful for tests, and when bootstrapping structInfo - printf__deps: ['_formatString'], + printf__deps: ['_formatString' +#if MINIMAL_RUNTIME + , '$intArrayToString' +#endif + ], printf: function(format, varargs) { // int printf(const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html From d8c014e29bfec2f26fa7650f406b7bee10d477db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 1 Feb 2020 20:35:23 +0200 Subject: [PATCH 06/17] Stack functions are not a JS library function in Wasm backend. --- src/library_html5.js | 8 ++++---- src/library_stack_trace.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/library_html5.js b/src/library_html5.js index 5ff82e72e9612..9f36984c3a11e 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -175,7 +175,7 @@ var LibraryJSEvents = { }, #if USE_PTHREADS -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !WASM_BACKEND queueEventHandlerOnThread_iiii__deps: ['$stackSave', '$stackAlloc', '$stackRestore'], #endif queueEventHandlerOnThread_iiii: function(targetThread, eventHandlerFunc, eventTypeId, eventData, userData) { @@ -2824,7 +2824,7 @@ var LibraryJSEvents = { }, emscripten_set_offscreencanvas_size_on_target_thread_js__deps: ['$stringToNewUTF8' -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !WASM_BACKEND , '$stackSave', '$stackAlloc', '$stackRestore' #endif ], @@ -2887,7 +2887,7 @@ var LibraryJSEvents = { #endif _set_canvas_element_size__deps: ['emscripten_set_canvas_element_size' -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !WASM_BACKEND , '$stackSave', '$stackAlloc', '$stackRestore' #endif ], @@ -2964,7 +2964,7 @@ var LibraryJSEvents = { // JavaScript-friendly API, returns pair [width, height] _get_canvas_element_size__deps: ['emscripten_get_canvas_element_size' -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !WASM_BACKEND , '$stackSave', '$stackAlloc', '$stackRestore' #endif ], diff --git a/src/library_stack_trace.js b/src/library_stack_trace.js index 8a05fe7d1c9d3..a7ac2850b70f6 100644 --- a/src/library_stack_trace.js +++ b/src/library_stack_trace.js @@ -1,7 +1,7 @@ var LibraryStackTrace = { $demangle__deps: [ -#if MINIMAL_RUNTIME +#if MINIMAL_RUNTIME && !WASM_BACKEND '$stackSave', '$stackAlloc', '$stackRestore' #if ASSERTIONS , '$warnOnce' From 6ef4ad997771a3dfb029d82445297ca5f7737800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 1 Feb 2020 20:44:00 +0200 Subject: [PATCH 07/17] Cleanup --- src/library_syscall.js | 3 --- src/settings.js | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index 4348d4a4adfcf..91ea45f33a0d7 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -227,9 +227,6 @@ var SyscallsLibrary = { _emscripten_syscall_mmap2__deps: ['memalign', 'memset', '$SYSCALLS', #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM '$FS', -#endif -#if MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have a global PAGE_SIZE runtime variable. - 'getpagesize' #endif ], _emscripten_syscall_mmap2: function(addr, len, prot, flags, fd, off) { diff --git a/src/settings.js b/src/settings.js index 01cacd4d81a45..d09f24b31f9fd 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1626,7 +1626,7 @@ var SUPPORT_ERRNO = 1; // opts are quite hacky, and work around limitations in Closure and other parts // of the build system, so they may not work in all generated programs (But can // be useful for really small programs) -var MINIMAL_RUNTIME = 1; +var MINIMAL_RUNTIME = 0; // If set to 1, MINIMAL_RUNTIME will utilize streaming WebAssembly compilation, // where WebAssembly module is compiled already while it is being downloaded. From 5c7978c9048c9df7713668477fbef5b6d6b03f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 1 Feb 2020 20:45:57 +0200 Subject: [PATCH 08/17] cleanup --- src/library_syscall.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index 91ea45f33a0d7..e147e6e4f1847 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -230,7 +230,6 @@ var SyscallsLibrary = { #endif ], _emscripten_syscall_mmap2: function(addr, len, prot, flags, fd, off) { -#endif off <<= 12; // undo pgoffset var ptr; var allocated = false; From 0f958f4172bf57221fffacbd5f02a7e775f8d166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 1 Feb 2020 21:17:47 +0200 Subject: [PATCH 09/17] assert() behind ASSERTIONS. --- src/Fetch.js | 2 ++ src/library_formatString.js | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/Fetch.js b/src/Fetch.js index 1b9361d60284b..26184d0158852 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -325,7 +325,9 @@ function __emscripten_fetch_xhr(fetch, onsuccess, onerror, onprogress, onreadyst xhr.open(requestMethod, url_, !fetchAttrSynchronous, userNameStr, passwordStr); if (!fetchAttrSynchronous) xhr.timeout = timeoutMsecs; // XHR timeout field is only accessible in async XHRs, and must be set after .open() but before .send(). xhr.url_ = url_; // Save the url for debugging purposes (and for comparing to the responseURL that server side advertised) +#if ASSERTIONS assert(!fetchAttrStreamData, 'streaming uses moz-chunked-arraybuffer which is no longer supported; TODO: rewrite using fetch()'); +#endif xhr.responseType = 'arraybuffer'; if (overriddenMimeType) { diff --git a/src/library_formatString.js b/src/library_formatString.js index 09082d2bc4edb..5b685237229ec 100644 --- a/src/library_formatString.js +++ b/src/library_formatString.js @@ -10,7 +10,9 @@ mergeInto(LibraryManager.library, { // Returns the resulting string string as a character array. _formatString__deps: ['_reallyNegative'], _formatString: function(format, varargs) { +#if ASSERTIONS assert((varargs & 3) === 0); +#endif var textIndex = format; var argIndex = varargs; // This must be called before reading a double or i64 vararg. It will bump the pointer properly. @@ -19,11 +21,15 @@ mergeInto(LibraryManager.library, { if (type === 'double' || type === 'i64') { // move so the load is aligned if (ptr & 7) { +#if ASSERTIONS assert((ptr & 7) === 4); +#endif ptr += 4; } } else { +#if ASSERTIONS assert((ptr & 3) === 0); +#endif } return ptr; } @@ -40,7 +46,9 @@ mergeInto(LibraryManager.library, { {{{ makeGetValue('argIndex', 4, 'i32', undefined, undefined, true, 4) }}}]; argIndex += 8; } else { +#if ASSERTIONS assert((argIndex & 3) === 0); +#endif type = 'i32'; // varargs are always i32, i64, or double ret = {{{ makeGetValue('argIndex', 0, 'i32', undefined, undefined, true) }}}; argIndex += 4; From b7ff1d3f14df567546717d2fcb37774a70db790d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 1 Feb 2020 21:31:04 +0200 Subject: [PATCH 10/17] Fix Closure + Wasm2JS build. --- src/promise_polyfill.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/promise_polyfill.js b/src/promise_polyfill.js index 8ebc4114c30ef..e4e3483ca209b 100644 --- a/src/promise_polyfill.js +++ b/src/promise_polyfill.js @@ -23,6 +23,8 @@ // THE SOFTWARE. //============================================================================== +/** @suppress{duplicate} This is already defined in from Closure's built-in + externs.zip//es6.js, Closure should not yell when seeing this again. */ var Promise = (function() { function noop() {} From b3eb4828998d1147309b6e5317567e958a2ab115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 3 Feb 2020 12:13:26 +0200 Subject: [PATCH 11/17] Flake and fix dladdr --- src/library.js | 2 +- tests/test_core.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/library.js b/src/library.js index f2f8494c65ab4..0bfee3500d6c7 100644 --- a/src/library.js +++ b/src/library.js @@ -1849,7 +1849,7 @@ LibraryManager.library = { dladdr__sig: 'iii', dladdr: function(addr, info) { // report all function pointers as coming from this program itself XXX not really correct in any way - var fname = __get_executable_name(); // XXX leak + var fname = stringToNewUTF8(__get_executable_name()); // XXX leak {{{ makeSetValue('info', 0, 'fname', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE, '0', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE*2, '0', 'i32') }}}; diff --git a/tests/test_core.py b/tests/test_core.py index 4a335febb1102..25671ddce7c37 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -247,6 +247,7 @@ def decorated(self, *args, **kwargs): return decorated return decorator + class TestCoreBase(RunnerCore): def is_wasm2js(self): return self.is_wasm_backend() and not self.get_setting('WASM') @@ -5150,7 +5151,7 @@ def test_utime(self): @no_minimal_runtime('MINIMAL_RUNTIME does not have getValue() and setValue() (TODO add it to a JS library function to get it in)') def test_utf(self): self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well - self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_malloc',]) + self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_malloc']) self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['getValue', 'setValue', 'UTF8ToString', 'stringToUTF8']) self.do_run_in_out_file_test('tests', 'core', 'test_utf') @@ -5167,7 +5168,7 @@ def test_utf8(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$AsciiToString', '$stringToAscii', '$writeAsciiToMemory']) else: self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', - ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) + ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) self.emcc_args += ['-std=c++11'] self.do_run(open(path_from_root('tests', 'utf8.cpp')).read(), 'OK.') From 7375c209dffcca253e3414a0795b1a8959b9be6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 3 Feb 2020 13:29:43 +0200 Subject: [PATCH 12/17] Revise fflush() behavior in MINIMAL_RUNTIME --- src/postamble_minimal.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 049c9f55b493b..c004eff1c6f41 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -20,10 +20,10 @@ function run() { {{{ getQuoted('ATEXITS') }}} #endif -#if FILESYSTEM && (ASSERTIONS || IN_TEST_HARNESS) - // fflush() filesystem stdio for test harness. For production use, instead print full lines to avoid this kind of - // lazy behavior. - _fflush(); +#if IN_TEST_HARNESS + // fflush() filesystem stdio for test harness, since there are existing tests that depend on this behavior. + // For production use, instead print full lines to avoid this kind of lazy behavior. + if (typeof _fflush !== 'undefined') _fflush(); #endif #if ASSERTIONS From 1ee137238dc82ceda16d6cf83407a19bac47fd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 3 Feb 2020 14:39:24 +0200 Subject: [PATCH 13/17] Drop memcpy and memset by default --- emcc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index a9c5c0fc44023..8719b415a4b09 100755 --- a/emcc.py +++ b/emcc.py @@ -1250,9 +1250,10 @@ def is_supported_link_flag(f): link_flags = [f for f in link_flags if is_supported_link_flag(f[1])] if shared.Settings.MINIMAL_RUNTIME: - # Remove the default exported functions 'malloc', 'free' - those should only be linked in if used - for to_remove in ['malloc', 'free']: - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) + # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used + for to_remove in ['malloc', 'free', 'memcpy', 'memset']: + if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) if shared.Settings.STACK_OVERFLOW_CHECK: if shared.Settings.MINIMAL_RUNTIME: From cb62bc67ec16b35be974131db78ff524f3ccc983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 3 Feb 2020 14:49:08 +0200 Subject: [PATCH 14/17] Fix deletion of DEFAULT_LIBRARY_FUNCS_TO_INCLUDE exports --- emcc.py | 12 ++++++------ src/library.js | 2 +- tests/test_other.py | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/emcc.py b/emcc.py index 8719b415a4b09..5829782aa367b 100755 --- a/emcc.py +++ b/emcc.py @@ -1109,6 +1109,12 @@ def get_last_setting_change(setting): # Apply -s settings in newargs here (after optimization levels, so they can override them) apply_settings(settings_changes) + if shared.Settings.MINIMAL_RUNTIME or 'MINIMAL_RUNTIME=1' in settings_changes: + # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used + for to_remove in ['malloc', 'free', 'memcpy', 'memset', 'emscripten_get_heap_size']: + if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) + shared.verify_settings() def filter_out_dynamic_libs(inputs): @@ -1249,12 +1255,6 @@ def is_supported_link_flag(f): link_flags = [f for f in link_flags if is_supported_link_flag(f[1])] - if shared.Settings.MINIMAL_RUNTIME: - # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used - for to_remove in ['malloc', 'free', 'memcpy', 'memset']: - if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) - if shared.Settings.STACK_OVERFLOW_CHECK: if shared.Settings.MINIMAL_RUNTIME: shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$abortStackOverflow'] diff --git a/src/library.js b/src/library.js index 0bfee3500d6c7..fc1ad6b116d19 100644 --- a/src/library.js +++ b/src/library.js @@ -467,7 +467,7 @@ LibraryManager.library = { }, emscripten_get_heap_size: function() { - return HEAP8.length; + return HEAPU8.length; }, emscripten_get_sbrk_ptr__asm: true, diff --git a/tests/test_other.py b/tests/test_other.py index c75c4db0d4869..2a3cd2e76ed67 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -9624,11 +9624,11 @@ def test_minimal_runtime_code_size(self): ] else: test_cases = [ - (asmjs + opts, hello_world_sources, {'a.html': 1223, 'a.js': 289, 'a.asm.js': 113, 'a.mem': 6}), - (opts, hello_world_sources, {'a.html': 1205, 'a.js': 633, 'a.wasm': 86}), - (asmjs + opts, hello_webgl_sources, {'a.html': 1353, 'a.js': 4921, 'a.asm.js': 11129, 'a.mem': 321}), - (opts, hello_webgl_sources, {'a.html': 1335, 'a.js': 4874, 'a.wasm': 8932}), - (opts, hello_webgl2_sources, {'a.html': 1335, 'a.js': 5361, 'a.wasm': 8932}) # Compare how WebGL2 sizes stack up with WebGL 1 + (asmjs + opts, hello_world_sources, {'a.html': 1222, 'a.js': 289, 'a.asm.js': 113, 'a.mem': 6}), + (opts, hello_world_sources, {'a.html': 1204, 'a.js': 630, 'a.wasm': 86}), + (asmjs + opts, hello_webgl_sources, {'a.html': 1352, 'a.js': 4896, 'a.asm.js': 11129, 'a.mem': 321}), + (opts, hello_webgl_sources, {'a.html': 1334, 'a.js': 4850, 'a.wasm': 8932}), + (opts, hello_webgl2_sources, {'a.html': 1334, 'a.js': 5357, 'a.wasm': 8932}) # Compare how WebGL2 sizes stack up with WebGL 1 ] success = True From f46a99537e7f9c02e104103deabc112c4167808d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 4 Feb 2020 19:23:51 +0200 Subject: [PATCH 15/17] Fix location of MINIMAL_RUNTIME reading --- emcc.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/emcc.py b/emcc.py index 5829782aa367b..9a36b1aaf1c18 100755 --- a/emcc.py +++ b/emcc.py @@ -1103,18 +1103,18 @@ def get_last_setting_change(setting): if 'WARN_ON_UNDEFINED_SYMBOLS=0' in settings_changes: shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = 0 + if shared.Settings.MINIMAL_RUNTIME or 'MINIMAL_RUNTIME=1' in settings_changes or 'MINIMAL_RUNTIME=2' in settings_changes: + # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used + for to_remove in ['malloc', 'free', 'memcpy', 'memset', 'emscripten_get_heap_size']: + if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) + # Set ASM_JS default here so that we can override it from the command line. shared.Settings.ASM_JS = 1 if options.opt_level > 0 else 2 # Apply -s settings in newargs here (after optimization levels, so they can override them) apply_settings(settings_changes) - if shared.Settings.MINIMAL_RUNTIME or 'MINIMAL_RUNTIME=1' in settings_changes: - # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used - for to_remove in ['malloc', 'free', 'memcpy', 'memset', 'emscripten_get_heap_size']: - if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) - shared.verify_settings() def filter_out_dynamic_libs(inputs): From 50dea26a99d6e4432c1aa15e3fe6889bb077fe0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 4 Feb 2020 19:26:23 +0200 Subject: [PATCH 16/17] Clear DEFAULT_LIBRARY_FUNCS_TO_INCLUDE for MINIMAL_RUNTIME --- emcc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 9a36b1aaf1c18..6bf4d260f7985 100755 --- a/emcc.py +++ b/emcc.py @@ -1105,9 +1105,7 @@ def get_last_setting_change(setting): if shared.Settings.MINIMAL_RUNTIME or 'MINIMAL_RUNTIME=1' in settings_changes or 'MINIMAL_RUNTIME=2' in settings_changes: # Remove the default exported functions 'malloc', 'free', etc. those should only be linked in if used - for to_remove in ['malloc', 'free', 'memcpy', 'memset', 'emscripten_get_heap_size']: - if to_remove in shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.remove(to_remove) + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = [] # Set ASM_JS default here so that we can override it from the command line. shared.Settings.ASM_JS = 1 if options.opt_level > 0 else 2 From ce20cb4c55da63e2a51e8d563cb300fc0a759289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 6 Feb 2020 16:39:30 +0200 Subject: [PATCH 17/17] Rename _get_executable_name to _getExecutableName. --- src/library.js | 10 +++++----- src/library_wasi.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library.js b/src/library.js index fc1ad6b116d19..6aadf579f55a0 100644 --- a/src/library.js +++ b/src/library.js @@ -746,7 +746,7 @@ LibraryManager.library = { // to limitations in the system libraries (we can't easily add a global // ctor to create the environment without it always being linked in with // libc). - __buildEnvironment__deps: ['$ENV', '_get_executable_name'], + __buildEnvironment__deps: ['$ENV', '_getExecutableName'], __buildEnvironment: function(environ) { // WARNING: Arbitrary limit! var MAX_ENV_VALUES = 64; @@ -765,7 +765,7 @@ LibraryManager.library = { ENV['HOME'] = '/home/web_user'; // Browser language detection #8751 ENV['LANG'] = ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8'; - ENV['_'] = __get_executable_name(); + ENV['_'] = __getExecutableName(); // Allocate memory. #if !MINIMAL_RUNTIME // TODO: environment support in MINIMAL_RUNTIME poolPtr = getMemory(TOTAL_ENV_SIZE); @@ -1844,12 +1844,12 @@ LibraryManager.library = { } }, - dladdr__deps: ['$stringToNewUTF8', '_get_executable_name'], + dladdr__deps: ['$stringToNewUTF8', '_getExecutableName'], dladdr__proxy: 'sync', dladdr__sig: 'iii', dladdr: function(addr, info) { // report all function pointers as coming from this program itself XXX not really correct in any way - var fname = stringToNewUTF8(__get_executable_name()); // XXX leak + var fname = stringToNewUTF8(__getExecutableName()); // XXX leak {{{ makeSetValue('info', 0, 'fname', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE, '0', 'i32') }}}; {{{ makeSetValue('info', Runtime.QUANTUM_SIZE*2, '0', 'i32') }}}; @@ -5161,7 +5161,7 @@ LibraryManager.library = { abort('stack overflow') }, - _get_executable_name: function() { + _getExecutableName: function() { #if MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have a global runtime variable thisProgram #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE && process['argv'].length > 1) { diff --git a/src/library_wasi.js b/src/library_wasi.js index 6084d841ca7dd..d62581292594e 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -11,7 +11,7 @@ var WasiLibrary = { return _exit(code); }, - emscripten_get_environ__deps: ['$ENV', '_get_executable_name'], + emscripten_get_environ__deps: ['$ENV', '_getExecutableName'], emscripten_get_environ: function() { if (!_emscripten_get_environ.strings) { // Default values. @@ -23,7 +23,7 @@ var WasiLibrary = { 'HOME': '/home/web_user', // Browser language detection #8751 'LANG': ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8', - '_': __get_executable_name() + '_': __getExecutableName() }; // Apply the user-provided values, if any. for (var x in ENV) {