From 07010b933d76dad1bdd71d55c3ddc2d8766833d9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 27 Feb 2024 15:36:32 -0800 Subject: [PATCH] [wasm2js] Remove all handling for external memory file (#21217) We have a lot of support code and complexity in emscripten for handling of external memory files. However, its only ever used in wasm2js mode which is a legacy mode. The only reason we continue to support it here IIUC is because its slightly more space efficient than embedding the data as base64. For small programs like hello_world this is an over codesize win. For larger programs there is a regression in overall size in proportion to the amount of static data in the program. --- ChangeLog.md | 5 +- docs/emcc.txt | 48 ----- emcc.py | 5 +- .../docs/compiling/Building-Projects.rst | 1 - site/source/docs/getting_started/FAQ.rst | 11 +- site/source/docs/tools_reference/emcc.rst | 20 -- src/postamble_minimal.js | 7 - src/preamble.js | 85 --------- src/settings.js | 2 +- src/settings_internal.js | 5 - src/shell.js | 2 +- src/shell_minimal.js | 10 +- test/code_size/hello_webgl2_wasm2js.json | 14 +- test/code_size/hello_webgl_wasm2js.json | 14 +- test/code_size/hello_world_wasm2js.js | 60 +++--- test/code_size/hello_world_wasm2js.json | 14 +- test/common.py | 16 -- test/in_flight_memfile_request.c | 19 -- test/mem_init.cpp | 28 --- test/mem_init_request.cpp | 23 --- .../metadce/test_metadce_minimal_O0.gzsize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_browser.py | 178 +++--------------- test/test_core.py | 12 +- test/test_other.py | 59 +++--- tools/link.py | 107 ++--------- tools/minimal_runtime_shell.py | 8 - 30 files changed, 132 insertions(+), 631 deletions(-) delete mode 100644 test/in_flight_memfile_request.c delete mode 100644 test/mem_init.cpp delete mode 100644 test/mem_init_request.cpp diff --git a/ChangeLog.md b/ChangeLog.md index 21b9e4df01ed..640299121e83 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -25,6 +25,10 @@ See docs/process.md for more on how version tagging works. only exported on demand. This means that they must be added to `EXPORTED_RUNTIME_METHODS` for them to appear on the `Module` object. For now, this only effects users of `STRICT` mode. (#21439) +- Emscripten no longer supports `--memory-init-file` (i.e. extracting static + data into an external .mem file). This feature was only available under + wasm2js (`-sWASM=0`) anyway so this change will only affect users of this + setting. (#21217) 3.1.54 - 02/15/24 ----------------- @@ -62,7 +66,6 @@ See docs/process.md for more on how version tagging works. - Allow comments in response files. Any line starting with `#` is now ignored. This is useful when listing exported symbols. (#21330) - 3.1.53 - 01/29/24 ----------------- - The llvm version that emscripten uses was updated to 19.0.0 trunk. (#21165) diff --git a/docs/emcc.txt b/docs/emcc.txt index ea768325837c..e2a7903e5195 100644 --- a/docs/emcc.txt +++ b/docs/emcc.txt @@ -493,49 +493,6 @@ Options that are modified or new in *emcc* are listed below: Ports repos. After this operation is complete, this process will exit. -"--memory-init-file 0|1" - [link] Specifies whether to emit a separate memory initialization - file. - - Note: - - Note that this is only relevant when *not* emitting Wasm, as - Wasm embeds the memory init data in the Wasm binary. - - Possible values are: - - * "0": Do not emit a separate memory initialization file. - Instead keep the static initialization inside the generated - JavaScript as text. This is the default setting if compiling - with -O0 or -O1 link-time optimization flags. - - * "1": Emit a separate memory initialization file in binary - format. This is more efficient than storing it as text inside - JavaScript, but does mean you have another file to publish. - The binary file will also be loaded asynchronously, which - means "main()" will not be called until the file is downloaded - and applied; you cannot call any C functions until it arrives. - This is the default setting when compiling with -O2 or higher. - - Note: - - The safest way to ensure that it is safe to call C functions - (the initialisation file has loaded) is to call a notifier - function from "main()". - - Note: - - If you assign a network request to - "Module.memoryInitializerRequest" (before the script runs), - then it will use that request instead of automatically - starting a download for you. This is beneficial in that you - can, in your HTML, fire off a request for the memory init - file before the script actually arrives. For this to work, - the network request should be an XMLHttpRequest with - responseType set to "'arraybuffer'". (You can also put any - other object here, all it must provide is a ".response" - property containing an ArrayBuffer.) - "-Wwarn-absolute-paths" [compile+link] Enables warnings about the use of absolute paths in "-I" and "-L" command line directives. This is used to warn against @@ -604,11 +561,6 @@ Options that are modified or new in *emcc* are listed below: These rules only apply when linking. When compiling to object code (See *-c* below) the name of the output file is irrelevant. - Note: - - If "--memory-init-file" is used, a **.mem** file will be created - in addition to the generated **.js** and/or **.html** file. - "-c" [compile] Tells *emcc* to emit an object file which can then be linked with other object files to produce an executable. diff --git a/emcc.py b/emcc.py index 6cd88c9793b7..985ab6c78bdd 100644 --- a/emcc.py +++ b/emcc.py @@ -81,7 +81,7 @@ '--bind', '--closure', '--cpuprofiler', '--embed-file', '--emit-symbol-map', '--emrun', '--exclude-file', '--extern-post-js', '--extern-pre-js', '--ignore-dynamic-linking', '--js-library', - '--js-transform', '--memory-init-file', '--oformat', '--output_eol', + '--js-transform', '--oformat', '--output_eol', '--post-js', '--pre-js', '--preload-file', '--profiling-funcs', '--proxy-to-worker', '--shell-file', '--source-map-base', '--threadprofiler', '--use-preload-plugins' @@ -145,7 +145,6 @@ def __init__(self): self.emrun = False self.cpu_profiler = False self.memory_profiler = False - self.memory_init_file = None self.use_preload_cache = False self.use_preload_plugins = False self.valid_abspaths = [] @@ -1316,7 +1315,7 @@ def consume_arg_file(): ports.show_ports() should_exit = True elif check_arg('--memory-init-file'): - options.memory_init_file = int(consume_arg()) + exit_with_error('--memory-init-file is no longer supported') elif check_flag('--proxy-to-worker'): settings_changes.append('PROXY_TO_WORKER=1') elif check_arg('--valid-abspath'): diff --git a/site/source/docs/compiling/Building-Projects.rst b/site/source/docs/compiling/Building-Projects.rst index ecbf3ca543b8..72fdc611c3ad 100644 --- a/site/source/docs/compiling/Building-Projects.rst +++ b/site/source/docs/compiling/Building-Projects.rst @@ -92,7 +92,6 @@ which files are produced under which conditions: - ``emcc ... -o output.wasm`` omits generating either JavaScript or HTML launcher file, and produces a single Wasm file built in standalone mode as if the ``-sSTANDALONE_WASM`` setting had been used. The resulting file expects to be run with the `WASI ABI `_ - in particular, as soon as you initialize the module you must manually invoke either the ``_start`` export or (in the case of ``--no-entry``) the ``_initialize`` export before doing anything else with it. - ``emcc ... -o output.{html,js} -sWASM=0`` causes the compiler to target JavaScript, and therefore a ``.wasm`` file is not produced. - ``emcc ... -o output.{html,js} --emit-symbol-map`` produces a file ``output.{html,js}.symbols`` if WebAssembly is being targeted (``-sWASM=0`` not specified), or if JavaScript is being targeted and ``-Os``, ``-Oz`` or ``-O2`` or higher is specified, but debug level setting is ``-g1`` or lower (i.e. if symbols minification did occur). -- ``emcc ... -o output.{html,js} -sWASM=0 --memory-init-file 1`` causes the generation of ``output.{html,js}.mem`` memory initializer file. Passing ``-O2``, ``-Os`` or ``-Oz`` also implies ``--memory-init-file 1``. - ``emcc ... -o output.{html,js} -gsource-map`` generates a source map file ``output.wasm.map``. If targeting JavaScript with ``-sWASM=0``, the filename is ``output.{html,js}.map``. - ``emcc ... -o output.{html,js} --preload-file xxx`` directive generates a preloaded MEMFS filesystem file ``output.data``. - ``emcc ... -o output.{html,js} -sWASM={0,1} -sSINGLE_FILE`` merges JavaScript and WebAssembly code in the single output file ``output.{html,js}`` (in base64) to produce only one file for deployment. (If paired with ``--preload-file``, the preloaded ``.data`` file still exists as a separate file) diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst index 70af89cd98f3..be6b48b437a1 100644 --- a/site/source/docs/getting_started/FAQ.rst +++ b/site/source/docs/getting_started/FAQ.rst @@ -308,12 +308,11 @@ function `x` called before runtime initialization``, which is a check enabled in ``ASSERTIONS`` builds.) Calling a compiled function before a page has fully loaded can result in an -error, if the function relies on files that may not be present (for example the -:ref:`.mem ` file and :ref:`preloaded -` files are loaded asynchronously, and therefore if you just -place some JS that calls compiled code in a ``--post-js``, that code will be -called synchronously at the end of the combined JS file, potentially before the -asynchronous event happens, which is bad). +error, if the function relies on files that may not be present (for example +:ref:`preloaded ` files are loaded asynchronously, and +therefore if you just place some JS that calls compiled code in a ``--post-js``, +that code will be called synchronously at the end of the combined JS file, +potentially before the asynchronous event happens, which is bad). The easiest way to find out when loading is complete is to add a ``main()`` function, and within it call a JavaScript function to notify your code that diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index f39c6ddfaeb8..c3174f98801e 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -487,24 +487,6 @@ Options that are modified or new in *emcc* are listed below: [general] Shows the list of available projects in the Emscripten Ports repos. After this operation is complete, this process will exit. -.. _emcc-memory-init-file: - -``--memory-init-file 0|1`` - [link] - Specifies whether to emit a separate memory initialization file. - - .. note:: Note that this is only relevant when *not* emitting Wasm, as Wasm embeds the memory init data in the Wasm binary. - - Possible values are: - - - ``0``: Do not emit a separate memory initialization file. Instead keep the static initialization inside the generated JavaScript as text. This is the default setting if compiling with -O0 or -O1 link-time optimization flags. - - ``1``: Emit a separate memory initialization file in binary format. This is more efficient than storing it as text inside JavaScript, but does mean you have another file to publish. The binary file will also be loaded asynchronously, which means ``main()`` will not be called until the file is downloaded and applied; you cannot call any C functions until it arrives. This is the default setting when compiling with -O2 or higher. - - .. note:: The :ref:`safest way ` to ensure that it is safe to call C functions (the initialisation file has loaded) is to call a notifier function from ``main()``. - - .. note:: If you assign a network request to ``Module.memoryInitializerRequest`` (before the script runs), then it will use that request instead of automatically starting a download for you. This is beneficial in that you can, in your HTML, fire off a request for the memory init file before the script actually arrives. For this to work, the network request should be an XMLHttpRequest with responseType set to ``'arraybuffer'``. (You can also put any other object here, all it must provide is a ``.response`` property containing an ArrayBuffer.) - - ``-Wwarn-absolute-paths`` [compile+link] Enables warnings about the use of absolute paths in ``-I`` and ``-L`` command line directives. This is used to warn against unintentional use of absolute paths, which is sometimes dangerous when referring to nonportable local system headers. @@ -562,8 +544,6 @@ Options that are modified or new in *emcc* are listed below: These rules only apply when linking. When compiling to object code (See `-c` below) the name of the output file is irrelevant. - .. note:: If ``--memory-init-file`` is used, a **.mem** file will be created in addition to the generated **.js** and/or **.html** file. - .. _emcc-c: ``-c`` diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 5638a986cce9..a17fa3483235 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -221,13 +221,6 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { updateMemoryViews(); #endif -#if !MEM_INIT_IN_WASM && !SINGLE_FILE -#if ASSERTIONS - if (!Module['mem']) throw 'Must load memory initializer as an ArrayBuffer in to variable Module.mem before adding compiled output .js script to the DOM'; -#endif - HEAPU8.set(new Uint8Array(Module['mem']), {{{ GLOBAL_BASE }}}); -#endif - initRuntime(wasmExports); #if PTHREADS // Export Wasm module for pthread creation to access. diff --git a/src/preamble.js b/src/preamble.js index b53ad03f69dc..f1d093d61cdc 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -973,9 +973,6 @@ function createWasm() { #endif updateMemoryViews(); #endif -#if !MEM_INIT_IN_WASM - runMemoryInitializer(); -#endif #if '$wasmTable' in addedLibraryItems && !RELOCATABLE wasmTable = wasmExports['__indirect_function_table']; @@ -1123,88 +1120,6 @@ function getCompilerSetting(name) { } #endif // RETAIN_COMPILER_SETTINGS -#if !MEM_INIT_IN_WASM -var memoryInitializer = <<< MEM_INITIALIZER >>>; - -function runMemoryInitializer() { -#if PTHREADS - if (ENVIRONMENT_IS_PTHREAD) return; -#endif - if (!isDataURI(memoryInitializer)) { - memoryInitializer = locateFile(memoryInitializer); - } - if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { - var data = readBinary(memoryInitializer); - HEAPU8.set(data, {{{ GLOBAL_BASE }}}); - } else { - addRunDependency('memory initializer'); - var applyMemoryInitializer = (data) => { - if (data.byteLength) data = new Uint8Array(data); -#if ASSERTIONS - for (var i = 0; i < data.length; i++) { - assert(HEAPU8[{{{ GLOBAL_BASE }}} + i] === 0, "area for memory initializer should not have been touched before it's loaded"); - } -#endif - HEAPU8.set(data, {{{ GLOBAL_BASE }}}); - // Delete the typed array that contains the large blob of the memory initializer request response so that - // we won't keep unnecessary memory lying around. However, keep the XHR object itself alive so that e.g. - // its .status field can still be accessed later. - if (Module['memoryInitializerRequest']) delete Module['memoryInitializerRequest'].response; - removeRunDependency('memory initializer'); - }; - var doBrowserLoad = () => { - readAsync(memoryInitializer, applyMemoryInitializer, () => { - var e = new Error('could not load memory initializer ' + memoryInitializer); -#if MODULARIZE - readyPromiseReject(e); -#else - throw e; -#endif - }); - }; -#if SUPPORT_BASE64_EMBEDDING - var memoryInitializerBytes = tryParseAsDataURI(memoryInitializer); - if (memoryInitializerBytes) { - applyMemoryInitializer(memoryInitializerBytes.buffer); - } else -#endif - if (Module['memoryInitializerRequest']) { - // a network request has already been created, just use that - var useRequest = () => { - var request = Module['memoryInitializerRequest']; - var response = request.response; - if (request.status !== 200 && request.status !== 0) { -#if SUPPORT_BASE64_EMBEDDING - var data = tryParseAsDataURI(Module['memoryInitializerRequestURL']); - if (data) { - response = data.buffer; - } else { -#endif - // If you see this warning, the issue may be that you are using locateFile and defining it in JS. That - // means that the HTML file doesn't know about it, and when it tries to create the mem init request early, does it to the wrong place. - // Look in your browser's devtools network console to see what's going on. - console.warn('a problem seems to have happened with Module.memoryInitializerRequest, status: ' + request.status + ', retrying ' + memoryInitializer); - doBrowserLoad(); - return; -#if SUPPORT_BASE64_EMBEDDING - } -#endif - } - applyMemoryInitializer(response); - }; - if (Module['memoryInitializerRequest'].response) { - setTimeout(useRequest, 0); // it's already here; but, apply it asynchronously - } else { - Module['memoryInitializerRequest'].addEventListener('load', useRequest); // wait for it - } - } else { - // fetch it from the network ourselves - doBrowserLoad(); - } - } -} -#endif // MEM_INIT_IN_WASM == 0 - #if MAIN_MODULE && ASYNCIFY // With MAIN_MODULE + ASYNCIFY the normal method of placing stub functions in // wasmImports for as-yet-undefined symbols doesn't work since ASYNCIFY then diff --git a/src/settings.js b/src/settings.js index 0339d4697474..a77bfaee6cfc 100644 --- a/src/settings.js +++ b/src/settings.js @@ -959,7 +959,7 @@ var INCOMING_MODULE_JS_API = [ 'onCustomMessage', 'onExit', 'onFree', 'onFullScreen', 'onMalloc', 'onRealloc', 'onRuntimeInitialized', 'postMainLoop', 'postRun', 'preInit', 'preMainLoop', 'preRun', - 'preinitializedWebGLContext', 'memoryInitializerRequest', 'preloadPlugins', + 'preinitializedWebGLContext', 'preloadPlugins', 'print', 'printErr', 'quit', 'setStatus', 'statusMessage', 'stderr', 'stdin', 'stdout', 'thisProgram', 'wasm', 'wasmBinary', 'websocket' ]; diff --git a/src/settings_internal.js b/src/settings_internal.js index 60a77da6b4f9..c27582b27014 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -143,11 +143,6 @@ var AUDIO_WORKLET_FILE = ''; // Base URL the source mapfile, if relevant var SOURCE_MAP_BASE = ''; -// When this is false we use an external memory init file -// See --memory-init-file. When not using wasm2js this flag is ignored, and -// this setting will always be true. -var MEM_INIT_IN_WASM = true; - // If set to 1, src/base64Utils.js will be included in the bundle. // This is set internally when needed (SINGLE_FILE) var SUPPORT_BASE64_EMBEDDING = false; diff --git a/src/shell.js b/src/shell.js index 3526116fe065..b9216aa37b25 100644 --- a/src/shell.js +++ b/src/shell.js @@ -439,7 +439,7 @@ if (ENVIRONMENT_IS_NODE) { // Merge back in the overrides Object.assign(Module, moduleOverrides); // Free the object hierarchy contained in the overrides, this lets the GC -// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. +// reclaim data used. moduleOverrides = null; #if ASSERTIONS checkIncomingModuleAPI(); diff --git a/src/shell_minimal.js b/src/shell_minimal.js index 5dcfd039a1f9..4a7eae59134e 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -82,7 +82,7 @@ if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_SHELL) { #endif #if !SINGLE_FILE -#if ENVIRONMENT_MAY_BE_NODE && ((WASM == 1 && (!WASM2JS || !MEM_INIT_IN_WASM)) || WASM == 2) +#if ENVIRONMENT_MAY_BE_NODE && ((WASM == 1 && !WASM2JS) || WASM == 2) // Wasm or Wasm2JS loading: if (ENVIRONMENT_IS_NODE) { @@ -95,13 +95,10 @@ if (ENVIRONMENT_IS_NODE) { Module['wasm'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.wasm'); #endif #endif -#if !MEM_INIT_IN_WASM - Module['mem'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.mem'); -#endif } #endif -#if ENVIRONMENT_MAY_BE_SHELL && ((WASM == 1 && (!WASM2JS || !MEM_INIT_IN_WASM)) || WASM == 2) +#if ENVIRONMENT_MAY_BE_SHELL && ((WASM == 1 && !WASM2JS) || WASM == 2) if (ENVIRONMENT_IS_SHELL) { #if WASM == 2 if (typeof WebAssembly != 'undefined') Module['wasm'] = read('{{{ TARGET_BASENAME }}}.wasm', 'binary'); @@ -111,9 +108,6 @@ if (ENVIRONMENT_IS_SHELL) { Module['wasm'] = read('{{{ TARGET_BASENAME }}}.wasm', 'binary'); #endif #endif -#if !MEM_INIT_IN_WASM - Module['mem'] = read('{{{ TARGET_BASENAME }}}.mem', 'binary'); -#endif } #endif diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index 26f088bfbae7..d3bb6d57bf6b 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,8 @@ { - "a.html": 567, - "a.html.gz": 379, - "a.js": 17800, - "a.js.gz": 7981, - "a.mem": 3123, - "a.mem.gz": 2693, - "total": 21490, - "total_gz": 11053 + "a.html": 354, + "a.html.gz": 266, + "a.js": 22323, + "a.js.gz": 11632, + "total": 22677, + "total_gz": 11898 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index 438d4423d35c..16ce634d5034 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,8 @@ { - "a.html": 567, - "a.html.gz": 379, - "a.js": 17272, - "a.js.gz": 7814, - "a.mem": 3123, - "a.mem.gz": 2693, - "total": 20962, - "total_gz": 10886 + "a.html": 354, + "a.html.gz": 266, + "a.js": 21794, + "a.js.gz": 11450, + "total": 22148, + "total_gz": 11716 } diff --git a/test/code_size/hello_world_wasm2js.js b/test/code_size/hello_world_wasm2js.js index 90abfb3c8c62..d81d12e761bf 100644 --- a/test/code_size/hello_world_wasm2js.js +++ b/test/code_size/hello_world_wasm2js.js @@ -1,19 +1,30 @@ -var c = Module, g, h, k = new TextDecoder("utf8"), l; +var d = Module, g, h, k = new TextDecoder("utf8"), l; -function d(b) { - this.exports = function(f) { - function m(e) { - e.set = function(a, n) { - this[a] = n; +function e(b) { + this.exports = function(r) { + function u(c) { + c.set = function(a, f) { + this[a] = f; }; - e.get = function(a) { + c.get = function(a) { return this[a]; }; - return e; + return c; } - return function(e) { - var a = new ArrayBuffer(16777216), n = e.a.a; - e = m([]); + function x(c, a, f) { + for (var v, p = 0, t = a, w = f.length, y = a + (3 * w >> 2) - ("=" == f[w - 2]) - ("=" == f[w - 1]); p < w; p += 4) a = m[f.charCodeAt(p + 1)], + v = m[f.charCodeAt(p + 2)], c[t++] = m[f.charCodeAt(p)] << 2 | a >> 4, t < y && (c[t++] = a << 4 | v >> 2), + t < y && (c[t++] = v << 6 | m[f.charCodeAt(p + 3)]); + } + for (var q, m = new Uint8Array(123), n = 25; 0 <= n; --n) m[48 + n] = 52 + n, m[65 + n] = n, + m[97 + n] = 26 + n; + m[43] = 62; + m[47] = 63; + return function(c) { + var a = new ArrayBuffer(16777216), f = new Uint8Array(a), v = c.a.a; + q = f; + x(q, 1024, "aGVsbG8h"); + c = u([]); return { b: Object.create(Object.prototype, { grow: {}, @@ -24,33 +35,33 @@ function d(b) { } }), c: function() {}, - d: function(p, q) { - n(1024); + d: function(p, t) { + v(1024); return 0; }, - e: e + e: c }; - }(f); + }(r); }(b); } -(function(b, f) { +(function(b, r) { return { - then: function(m) { - m({ - instance: new d(f) + then: function(u) { + u({ + instance: new e(r) }); } }; -})(c.wasm, { +})(d.wasm, { a: { a: b => { - var f = console, m = f.log; + var r = console, u = r.log; if (b) { - for (var e = b + void 0, a = b; !(a >= e) && g[a]; ) ++a; - b = k.decode(g.subarray(b, a)); + for (var x = b + void 0, q = b; !(q >= x) && g[q]; ) ++q; + b = k.decode(g.subarray(b, q)); } else b = ""; - m.call(f, b); + u.call(r, b); } } }).then((b => { @@ -58,7 +69,6 @@ function d(b) { l = b.d; h = b.b; g = new Uint8Array(h.buffer); - g.set(new Uint8Array(c.mem), 1024); b.c(); l(); })); \ No newline at end of file diff --git a/test/code_size/hello_world_wasm2js.json b/test/code_size/hello_world_wasm2js.json index 6c26b7a43f59..80d9448e1fab 100644 --- a/test/code_size/hello_world_wasm2js.json +++ b/test/code_size/hello_world_wasm2js.json @@ -1,10 +1,8 @@ { - "a.html": 671, - "a.html.gz": 430, - "a.js": 708, - "a.js.gz": 444, - "a.mem": 6, - "a.mem.gz": 32, - "total": 1385, - "total_gz": 906 + "a.html": 323, + "a.html.gz": 253, + "a.js": 1060, + "a.js.gz": 636, + "total": 1383, + "total_gz": 889 } diff --git a/test/common.py b/test/common.py index bb258b3238fa..fc74c360ef74 100644 --- a/test/common.py +++ b/test/common.py @@ -847,17 +847,6 @@ def setup_node_pthreads(self): self.js_engines = [nodejs] self.node_args += shared.node_pthread_flags(nodejs) - def uses_memory_init_file(self): - if self.get_setting('SIDE_MODULE') or self.is_wasm(): - return False - - if '--memory-init-file' in self.emcc_args: - return int(self.emcc_args[self.emcc_args.index('--memory-init-file') + 1]) - - # side modules handle memory differently; binaryen puts the memory in the wasm module - opt_supports = any(opt in self.emcc_args for opt in ('-O2', '-O3', '-Os', '-Oz')) - return opt_supports - def set_temp_dir(self, temp_dir): self.temp_dir = temp_dir self.canonical_temp_dir = get_canonical_temp_dir(self.temp_dir) @@ -1104,11 +1093,6 @@ def build(self, filename, libraries=None, includes=None, force_c=False, js_outfi self.run_process(cmd, stderr=self.stderr_redirect if not DEBUG else None) self.assertExists(output) - if js_outfile and self.uses_memory_init_file(): - src = read_file(output) - # side memory init file, or an empty one in the js - assert ('/* memory initializer */' not in src) or ('/* memory initializer */ allocate([]' in src) - return output def get_func(self, src, name): diff --git a/test/in_flight_memfile_request.c b/test/in_flight_memfile_request.c deleted file mode 100644 index e0be9e4b8e7c..000000000000 --- a/test/in_flight_memfile_request.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2015 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#include -#include - -int main() { - int result = EM_ASM_INT({ - return !!Module['memoryInitializerRequest']; - }); - printf("memory init request: %d\n", result); - REPORT_RESULT(result); - return 0; -} - diff --git a/test/mem_init.cpp b/test/mem_init.cpp deleted file mode 100644 index b6911172ddd1..000000000000 --- a/test/mem_init.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 The Emscripten Authors. All rights reserved. -// Emscripten is available under two separate licenses, the MIT license and the -// University of Illinois/NCSA Open Source License. Both these licenses can be -// found in the LICENSE file. - -#include -#include -#include - -extern "C" { - -int noted = 1; - -const char* EMSCRIPTEN_KEEPALIVE note(int n) { - EM_ASM({ out([$0, $1]) }, n, noted); - noted = noted | n; - EM_ASM({ out(['noted is now', $0]) }, noted); - return "silly-string"; -} - -} - -int main() { - EM_ASM( myJSCallback() ); // calls a global JS func - assert(noted == 3); - return 0; -} - diff --git a/test/mem_init_request.cpp b/test/mem_init_request.cpp deleted file mode 100644 index 2d1ad4415e51..000000000000 --- a/test/mem_init_request.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Emscripten Authors. All rights reserved. -// Emscripten is available under two separate licenses, the MIT license and the -// University of Illinois/NCSA Open Source License. Both these licenses can be -// found in the LICENSE file. - -#include -#include -#include - -int main() { - const char *hello = "hello world"; - putc('g', stdout); - putc('o', stdout); - putc('!', stdout); - assert(strchr(hello, 'l') == hello + 2); - assert(strchr(hello, 'w') == hello + 6); - putc('d', stdout); - putc('o', stdout); - putc('n', stdout); - putc('e', stdout); - return 0; -} - diff --git a/test/other/metadce/test_metadce_minimal_O0.gzsize b/test/other/metadce/test_metadce_minimal_O0.gzsize index 93ab05de17c2..d24406713de2 100644 --- a/test/other/metadce/test_metadce_minimal_O0.gzsize +++ b/test/other/metadce/test_metadce_minimal_O0.gzsize @@ -1 +1 @@ -6858 +6851 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 4a53ea86c7ff..7f1ac7cb5897 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -18751 +18720 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 08e9897ea671..545b21525a14 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58097 +58034 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 9874731bce55..996164ae6936 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -31628 +31565 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 920f0bb214c8..690cc6176f33 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57049 +56937 diff --git a/test/test_browser.py b/test/test_browser.py index 5527899a241a..716807240240 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -753,21 +753,14 @@ def test_sdl_surface_lock_opts(self): # Test Emscripten-specific extensions to optimize SDL_LockSurface and SDL_UnlockSurface. self.reftest('hello_world_sdl.cpp', 'htmltest.png', args=['-DTEST_SDL_LOCK_OPTS', '-lSDL', '-lGL']) - @parameterized({ - '': ([],), - 'meminit_file': (['--memory-init-file=1', '-sWASM=0'],), - }) @also_with_wasmfs - def test_sdl_image(self, args): - # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init + def test_sdl_image(self): + # load an image file, get pixel data. Also O2 coverage for --preload-file shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.jpg') src = test_file('browser/test_sdl_image.c') - if '-sWASM=0' in args: - self.require_wasm2js() - for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'), ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]: - self.btest_exit(src, args=args + [ + self.btest_exit(src, args=[ '-O2', '-lSDL', '-lGL', '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', '-DSCREENSHOT_BASENAME="' + basename + '"', '--use-preload-plugins' ]) @@ -2383,13 +2376,8 @@ def test_runtimelink(self): self.run_process([EMCC, 'supp.c', '-o', 'supp.wasm', '-sSIDE_MODULE', '-O2'] + self.get_emcc_args()) self.btest_exit('main.c', args=['-sMAIN_MODULE=2', '-O2', 'supp.wasm']) - @parameterized({ - '': ([],), - 'memfile': (['-sWASM=0', '--memory-init-file=1'],) - }) - def test_pre_run_deps(self, args): - if args: - self.require_wasm2js() + @also_with_wasm2js + def test_pre_run_deps(self): # Adding a dependency in preRun will delay run create_file('pre.js', ''' Module.preRun = () => { @@ -2402,61 +2390,10 @@ def test_pre_run_deps(self, args): }; ''') - self.btest('pre_run_deps.cpp', expected='10', args=args + ['--pre-js', 'pre.js']) - - @requires_wasm2js - def test_mem_init(self): - self.set_setting('WASM_ASYNC_COMPILATION', 0) - create_file('pre.js', ''' - function myJSCallback() { // called from main() - Module._note(1); - } - Module.preRun = () => { - addOnPreMain(() => Module._note(2)); - }; - ''') - create_file('post.js', ''' - Module._note(4); // this happens too early! and is overwritten when the mem init arrives - ''') - - args = ['-sWASM=0', '--pre-js', 'pre.js', '--post-js', 'post.js', '--memory-init-file', '1'] - - # with assertions, we notice when memory was written to too early - expected = 'abort:Assertion failed: native function `note` called before runtime initialization' - self.btest('mem_init.cpp', expected=expected, args=args) - # otherwise, we just overwrite - self.btest_exit('mem_init.cpp', args=args + ['-sASSERTIONS=0']) - - @requires_wasm2js - def test_mem_init_request(self): - def test(what, status): - print(what, status) - create_file('pre.js', ''' - var xhr = Module.memoryInitializerRequest = new XMLHttpRequest(); - xhr.open('GET', "''' + what + '''", true); - xhr.responseType = 'arraybuffer'; - xhr.send(null); - - console.warn = (x) => { - if (x.includes('a problem seems to have happened with Module.memoryInitializerRequest')) { - maybeReportResultToServer('got_error'); - } - console.log('WARNING: ' + x); - }; - ''') - self.btest('mem_init_request.cpp', expected=status, args=['-sWASM=0', '--pre-js', 'pre.js', '--memory-init-file', '1']) - - self.set_setting('EXIT_RUNTIME') - test('test.html.mem', 'exit:0') - test('nothing.nowhere', 'got_error') + self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js']) - @parameterized({ - '': ([],), - 'wasm2js': (['-sWASM=0', '--memory-init-file=1'],) - }) - def test_runtime_misuse(self, mode): - if mode: - self.require_wasm2js() + @also_with_wasm2js + def test_runtime_misuse(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall,$cwrap') post_prep = ''' var expected_ok = false; @@ -2538,14 +2475,14 @@ def test_runtime_misuse(self, mode): print('mem init, so async, call too early') create_file('post.js', post_prep + post_test + post_hook) - self.btest(filename, expected='600', args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args + mode, reporting=Reporting.NONE) + self.btest(filename, expected='600', args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args, reporting=Reporting.NONE) print('sync startup, call too late') create_file('post.js', post_prep + 'Module.postRun = () => { ' + post_test + ' };' + post_hook) - self.btest(filename, expected=str(second_code), args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args + mode, reporting=Reporting.NONE) + self.btest(filename, expected=str(second_code), args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args, reporting=Reporting.NONE) print('sync, runtime still alive, so all good') create_file('post.js', post_prep + 'expected_ok = true; Module.postRun = () => { ' + post_test + ' };' + post_hook) - self.btest(filename, expected='606', args=['--post-js', 'post.js'] + extra_args + mode, reporting=Reporting.NONE) + self.btest(filename, expected='606', args=['--post-js', 'post.js'] + extra_args, reporting=Reporting.NONE) def test_cwrap_early(self): self.btest(Path('browser/cwrap_early.cpp'), args=['-O2', '-sASSERTIONS', '--pre-js', test_file('browser/cwrap_early.js'), '-sEXPORTED_RUNTIME_METHODS=cwrap'], expected='0') @@ -2921,8 +2858,6 @@ def test_locate_file(self, args): ensure_dir('sub') if wasm: shutil.move('page.wasm', Path('sub/page.wasm')) - else: - shutil.move('page.html.mem', Path('sub/page.html.mem')) shutil.move('test.data', Path('sub/test.data')) self.run_browser('page.html', '/report_result?exit:0') @@ -2945,29 +2880,10 @@ def in_html(expected): self.compile_btest('src.cpp', ['-O2', '-g', '--shell-file', 'shell.html', '--pre-js', 'data.js', '-o', 'page.html', '-sSAFE_HEAP', '-sASSERTIONS', '-sFORCE_FILESYSTEM', '-sWASM=' + str(wasm)] + args, reporting=Reporting.JS_ONLY) if wasm: shutil.move('page.wasm', Path('sub/page.wasm')) - else: - shutil.move('page.html.mem', Path('sub/page.html.mem')) self.run_browser('page.html', '/report_result?exit:' + expected) in_html('0') - # verify that the mem init request succeeded in the latter case - if not wasm: - create_file('src.cpp', r''' - #include - #include - - int main() { - int result = EM_ASM_INT({ - return Module['memoryInitializerRequest'].status; - }); - printf("memory init request: %d\n", result); - return result; - } - ''') - - in_html('200') - @requires_graphics_hardware def test_glfw3_default_hints(self): self.btest_exit('test_glfw3_default_hints.c', args=['-sUSE_GLFW=3', '-lglfw', '-lGL']) @@ -2992,20 +2908,15 @@ def test_glfw3_hi_dpi_aware(self): self.btest_exit('test_glfw3_hi_dpi_aware.c', args=['-sUSE_GLFW=3', '-lGL']) @requires_graphics_hardware + @also_with_wasm2js @no_wasm64('SDL2 + wasm64') - @parameterized({ - '': ([],), - 'memfile': (['-sWASM=0', '--memory-init-file=1'],) - }) - def test_sdl2_image(self, args): - if args: - self.require_wasm2js() - # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init + def test_sdl2_image(self): + # load an image file, get pixel data. Also O2 coverage for --preload-file shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.jpg') for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'), ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]: - self.btest_exit('test_sdl2_image.c', 600, args=args + [ + self.btest_exit('test_sdl2_image.c', 600, args=[ '-O2', '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', @@ -3570,12 +3481,6 @@ def test_modularize(self): hello._main(); }); '''), - # Even without a mem init file, everything is async - (['-sEXPORT_NAME="HelloWorld"', '--memory-init-file', '0'], ''' - HelloWorld({ noInitialRun: true }).then(hello => { - hello._main(); - }); - '''), ]: print('test on', opts, args, code) # this test is synchronous, so avoid async startup due to wasm features @@ -4234,8 +4139,6 @@ def test_pthread_custom_pthread_main_url(self): create_file('shell.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function (path, prefix) {if (path.endsWith(".wasm")) {return prefix + path;} else {return "cdn/" + path;}}, ')) self.compile_btest('main.cpp', ['--shell-file', 'shell.html', '-pthread', '-sPTHREAD_POOL_SIZE', '-o', 'test.html'], reporting=Reporting.JS_ONLY) shutil.move('test.worker.js', Path('cdn/test.worker.js')) - if os.path.exists('test.html.mem'): - shutil.copyfile('test.html.mem', Path('cdn/test.html.mem')) self.run_browser('test.html', '/report_result?exit:0') # Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from. @@ -4313,23 +4216,13 @@ def test_pthread_call_async_on_main_thread(self): # global data section of the application memory area. @requires_threads def test_pthread_global_data_initialization(self): - # --memory-init-file mode disabled because WASM=0 does not seem to work with EXPORT_NAME - mem_init_modes = [[]] # ['-sWASM=0', '--memory-init-file', '0'], ['-sWASM=0', '--memory-init-file', '1']] - for mem_init_mode in mem_init_modes: - print(mem_init_mode) - for args in [['-sMODULARIZE', '-sEXPORT_NAME=MyModule', '--shell-file', test_file('shell_that_launches_modularize.html')], ['-O3']]: - self.btest_exit('pthread/test_pthread_global_data_initialization.c', args=args + mem_init_mode + ['-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) + for args in [['-sMODULARIZE', '-sEXPORT_NAME=MyModule', '--shell-file', test_file('shell_that_launches_modularize.html')], ['-O3']]: + self.btest_exit('pthread/test_pthread_global_data_initialization.c', args=args + ['-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) @requires_wasm2js @requires_threads def test_pthread_global_data_initialization_in_sync_compilation_mode(self): - if self.is_wasm64(): - self.skipTest('wasm2js is not compatible with MEMORY64') - mem_init_modes = [[], ['-sWASM=0', '--memory-init-file', '0'], ['-sWASM=0', '--memory-init-file', '1']] - for mem_init_mode in mem_init_modes: - print(mem_init_mode) - args = ['-sWASM_ASYNC_COMPILATION=0'] - self.btest_exit('pthread/test_pthread_global_data_initialization.c', args=args + mem_init_mode + ['-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) + self.btest_exit('pthread/test_pthread_global_data_initialization.c', args=['-sWASM_ASYNC_COMPILATION=0', '-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) # Test that emscripten_get_now() reports coherent wallclock times across all # pthreads, instead of each pthread independently reporting wallclock times @@ -4481,27 +4374,6 @@ def test_vanilla_html_when_proxying(self): create_file('test.html', '') self.run_browser('test.html', '/report_result?0') - @requires_wasm2js - @parameterized({ - 'O0': [('-O0',), '0'], - 'O1': [('-O1',), '0'], - 'O2': [('-O2',), '1'], - }) - def test_in_flight_memfile_request(self, args, expected): - # test the XHR for an asm.js mem init file being in flight already - self.emcc_args += args - self.set_setting('WASM', 0) - - print('plain html') - self.compile_btest('in_flight_memfile_request.c', ['-o', 'test.js']) - create_file('test.html', '') - # never when we provide our own HTML like this. - self.run_browser('test.html', '/report_result?0') - - print('default html') - # should happen when there is a mem init file (-O2+) - self.btest('in_flight_memfile_request.c', expected=expected) - @parameterized({ '': ([], 1), 'O1': (['-O1'], 1), @@ -5094,7 +4966,6 @@ def test_single_file_html(self): self.assertNotExists('test.js') self.assertNotExists('test.worker.js') self.assertNotExists('test.wasm') - self.assertNotExists('test.mem') # Tests that SINGLE_FILE works as intended in generated HTML with MINIMAL_RUNTIME @parameterized({ @@ -5108,7 +4979,6 @@ def test_minimal_runtime_single_file_html(self, opts): self.assertNotExists('test.js') self.assertNotExists('test.wasm') self.assertNotExists('test.asm.js') - self.assertNotExists('test.mem') self.assertNotExists('test.js') self.assertNotExists('test.worker.js') @@ -5340,16 +5210,10 @@ def test_no_declare_asm_module_exports_wasm_minimal_runtime(self, mode): '': ([],), 'modularize': (['-sMODULARIZE'],), }) - @parameterized({ - '': ([],), - 'wasm2js': (['-sWASM=0', '--memory-init-file', '0'],), - 'wasm2js_mem_init_file': (['-sWASM=0', '--memory-init-file', '1'],), - }) - def test_minimal_runtime_loader_shell(self, wasm_args, modularize): + @also_with_wasm2js + def test_minimal_runtime_loader_shell(self, args): args = ['-sMINIMAL_RUNTIME=2'] - if wasm_args: - self.require_wasm2js() - self.btest_exit('minimal_hello.c', args=args + wasm_args + modularize) + self.btest_exit('minimal_hello.c', args=args) # Tests that -sMINIMAL_RUNTIME works well in different build modes @parameterized({ diff --git a/test/test_core.py b/test/test_core.py index 8711e968dcad..ebf9842164ec 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5398,9 +5398,6 @@ def clean(out): self.do_runf('files.cpp', ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\n'), output_nicerizer=clean) - if self.uses_memory_init_file(): - self.assertExists('files.js.mem') - def test_files_m(self): # Test for Module.stdin etc. # needs to flush stdio streams @@ -8398,14 +8395,7 @@ def test_wasm2js(self): self.skipTest('redundant to test wasm2js in wasm2js* mode') self.set_setting('WASM', 0) self.do_core_test('test_hello_world.c') - # a mem init file is emitted just like with JS - expect_memory_init_file = self.uses_memory_init_file() - if expect_memory_init_file: - self.assertExists('test_hello_world.js.mem') - mem = read_binary('test_hello_world.js.mem') - self.assertTrue(mem[-1] != b'\0') - else: - self.assertNotExists('test_hello_world.js.mem') + self.assertNotExists('test_hello_world.js.mem') @no_sanitize('no wasm2js support yet in sanitizers') @requires_wasm2js diff --git a/test/test_other.py b/test/test_other.py index c909ee06a84d..72647882a8d5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -717,31 +717,25 @@ def test_js_transform(self): self.assertContained('disabling source maps because a js transform is being done', err) self.assertIn('transformed!', read_file('a.out.js')) - def test_js_mem_file(self): - for opts in [0, 1, 2, 3]: - print('mem init in', opts) + @parameterized({ + '': [[]], + 'O1': [['-O1']], + 'O2': [['-O2']], + 'O3': [['-O3']], + }) + def test_emcc_asm_v_wasm(self, opts): + for mode in ([], ['-sWASM=0']): self.clear() - self.run_process([EMCC, test_file('hello_world.c'), '-sWASM=0', '-O' + str(opts)]) - if opts >= 2: - self.assertExists('a.out.js.mem') - else: - self.assertNotExists('a.out.js.mem') - - def test_emcc_asm_v_wasm(self): - for opts in ([], ['-O1'], ['-O2'], ['-O3']): - print('opts', opts) - for mode in ([], ['-sWASM=0']): - self.clear() - wasm = '=0' not in str(mode) - print(' mode', mode, 'wasm?', wasm) - self.run_process([EMCC, test_file('hello_world.c'), '-sENVIRONMENT=node,shell'] + opts + mode) - self.assertExists('a.out.js') - if wasm: - self.assertExists('a.out.wasm') - for engine in config.JS_ENGINES: - print(' engine', engine) - out = self.run_js('a.out.js', engine=engine) - self.assertContained('hello, world!', out) + wasm = '=0' not in str(mode) + print(' mode', mode, 'wasm?', wasm) + self.run_process([EMCC, test_file('hello_world.c'), '-sENVIRONMENT=node,shell'] + opts + mode) + self.assertExists('a.out.js') + if wasm: + self.assertExists('a.out.wasm') + for engine in config.JS_ENGINES: + print(' engine', engine) + out = self.run_js('a.out.js', engine=engine) + self.assertContained('hello, world!', out) @crossplatform def test_emcc_cflags(self): @@ -9102,26 +9096,19 @@ def test_standalone_system_headers(self): }) def test_single_file(self, wasm2js): for (single_file_enabled, - meminit1_enabled, debug_enabled, - closure_enabled) in itertools.product([True, False], repeat=4): + closure_enabled) in itertools.product([True, False], repeat=3): # skip unhelpful option combinations - if meminit1_enabled and not wasm2js: - continue if closure_enabled and debug_enabled: continue expect_wasm = not wasm2js - expect_meminit = meminit1_enabled and wasm2js cmd = [EMCC, test_file('hello_world.c')] if single_file_enabled: - expect_meminit = False expect_wasm = False cmd += ['-sSINGLE_FILE'] - if meminit1_enabled: - cmd += ['--memory-init-file', '1'] if debug_enabled: cmd += ['-g'] if closure_enabled: @@ -9135,7 +9122,6 @@ def do_test(cmd): print(' '.join(cmd)) self.run_process(cmd) print(os.listdir('.')) - assert expect_meminit == (os.path.exists('a.out.mem') or os.path.exists('a.out.js.mem')) assert expect_wasm == os.path.exists('a.out.wasm') assert not os.path.exists('a.out.wat') self.assertContained('hello, world!', self.run_js('a.out.js')) @@ -10697,7 +10683,7 @@ def test_minimal_runtime_code_size(self, test_name, js, compare_js_output=False) '-DNDEBUG', '-ffast-math'] - wasm2js = ['-sWASM=0', '--memory-init-file', '1'] + wasm2js = ['-sWASM=0'] math_sources = [test_file('code_size/math.c')] hello_world_sources = [test_file('small_hello_world.c'), @@ -10738,7 +10724,6 @@ def print_percent(actual, expected): args = smallest_code_size_args[:] if js: - outputs += ['a.mem'] args += wasm2js test_name += '_wasm2js' else: @@ -14130,8 +14115,8 @@ def run(args, expect_bulk_mem): run(['-pthread'], expect_bulk_mem=True) def test_memory_init_file_unsupported(self): - err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Werror', '--memory-init-file=1']) - self.assertContained('error: --memory-init-file is only supported with -sWASM=0 [-Wunsupported] [-Werror]', err) + err = self.expect_fail([EMCC, test_file('hello_world.c'), '--memory-init-file=1']) + self.assertContained('error: --memory-init-file is no longer supported', err) @node_pthreads def test_node_pthreads_err_out(self): diff --git a/tools/link.py b/tools/link.py index f2f631dd5213..3c135be074e6 100644 --- a/tools/link.py +++ b/tools/link.py @@ -193,14 +193,6 @@ def setup_environment_settings(): exit_with_error('when building with multithreading enabled and a "-sENVIRONMENT=" directive is specified, it must include "worker" as a target! (Try e.g. -sENVIRONMENT=web,worker)') -def embed_memfile(options): - return (settings.SINGLE_FILE or - (settings.WASM2JS and not options.memory_init_file and - (not settings.MAIN_MODULE and - not settings.SIDE_MODULE and - not settings.GENERATE_SOURCE_MAP))) - - def generate_js_sym_info(): # Runs the js compiler to generate a list of all symbols available in the JS # libraries. This must be done separately for each linker invocation since the @@ -325,13 +317,7 @@ def should_run_binaryen_optimizer(): return settings.OPT_LEVEL >= 2 -def remove_trailing_zeros(memfile): - mem_data = utils.read_binary(memfile) - mem_data = mem_data.rstrip(b'\0') - utils.write_binary(memfile, mem_data) - - -def get_binaryen_passes(memfile): +def get_binaryen_passes(): passes = [] optimizing = should_run_binaryen_optimizer() # wasm-emscripten-finalize will strip the features section for us @@ -417,12 +403,6 @@ def check_human_readable_list(items): if settings.MEMORY64 == 2: passes += ['--memory64-lowering'] - if memfile: - passes += [ - f'--separate-data-segments={memfile}', - f'--pass-arg=separate-data-segments-global-base@{settings.GLOBAL_BASE}' - ] - if settings.BINARYEN_IGNORE_IMPLICIT_TRAPS: passes += ['--ignore-implicit-traps'] # normally we can assume the memory, if imported, has not been modified @@ -1477,19 +1457,7 @@ def check_memory_setting(setting): exit_with_error('closure compiler mode 2 assumes the code is asm.js, so not meaningful for wasm') if settings.WASM2JS: - if options.memory_init_file is None: - options.memory_init_file = settings.OPT_LEVEL >= 2 settings.MAYBE_WASM2JS = 1 - # when using wasm2js, if the memory segments are in the wasm then they - # end up converted by wasm2js into base64 encoded JS. alternatively, we - # can use a .mem file like asm.js used to. - # generally we follow what the options tell us to do (which is to use - # a .mem file in most cases, since it is binary & compact). however, for - # shared memory builds we must keep the memory segments in the wasm as - # they will be passive segments which the .mem format cannot handle. - settings.MEM_INIT_IN_WASM = not options.memory_init_file or settings.SINGLE_FILE or settings.SHARED_MEMORY - elif options.memory_init_file: - diagnostics.warning('unsupported', '--memory-init-file is only supported with -sWASM=0') if settings.AUTODEBUG: settings.REQUIRED_EXPORTS += ['setTempRet0'] @@ -1854,7 +1822,7 @@ def phase_post_link(options, state, in_wasm, wasm_target, target, js_syms): settings.TARGET_JS_NAME = os.path.basename(state.js_target) - metadata = phase_emscript(options, in_wasm, wasm_target, js_syms) + metadata = phase_emscript(in_wasm, wasm_target, js_syms) if settings.EMBIND_AOT: phase_embind_aot(wasm_target, js_syms) @@ -1865,24 +1833,21 @@ def phase_post_link(options, state, in_wasm, wasm_target, target, js_syms): if options.js_transform: phase_source_transforms(options) - if settings.MEM_INIT_IN_WASM: - memfile = None - else: - memfile = shared.replace_or_append_suffix(target, '.mem') - - phase_binaryen(target, options, wasm_target, memfile) + phase_binaryen(target, options, wasm_target) # If we are not emitting any JS then we are all done now if options.oformat != OFormat.WASM: - phase_final_emitting(options, state, target, wasm_target, memfile) + phase_final_emitting(options, state, target, wasm_target) @ToolchainProfiler.profile_block('emscript') -def phase_emscript(options, in_wasm, wasm_target, js_syms): +def phase_emscript(in_wasm, wasm_target, js_syms): # Emscripten logger.debug('emscript') - settings.SUPPORT_BASE64_EMBEDDING = embed_memfile(options) + # No need to support base64 embeddeding in wasm2js mode since + # the module is already in JS format. + settings.SUPPORT_BASE64_EMBEDDING = settings.SINGLE_FILE and not settings.WASM2JS if shared.SKIP_SUBPROCS: return @@ -1984,18 +1949,6 @@ def phase_source_transforms(options): save_intermediate('transformed') -@ToolchainProfiler.profile_block('memory initializer') -def phase_memory_initializer(memfile): - # For the wasm backend, we don't have any memory info in JS. All we need to do - # is set the memory initializer url. - global final_js - - src = read_file(final_js) - src = do_replace(src, '<<< MEM_INITIALIZER >>>', '"%s"' % os.path.basename(memfile)) - write_file(final_js + '.mem.js', src) - final_js += '.mem.js' - - # Unmangle previously mangled `import.meta` and `await import` references in # both main code and libraries. # See also: `preprocess` in parseTools.js. @@ -2025,7 +1978,7 @@ def create_worker_file(input_file, target_dir, output_file): @ToolchainProfiler.profile_block('final emitting') -def phase_final_emitting(options, state, target, wasm_target, memfile): +def phase_final_emitting(options, state, target, wasm_target): global final_js if shared.SKIP_SUBPROCS: @@ -2088,13 +2041,10 @@ def phase_final_emitting(options, state, target, wasm_target, memfile): # If we were asked to also generate HTML, do that if options.oformat == OFormat.HTML: generate_html(target, options, js_target, target_basename, - wasm_target, memfile) + wasm_target) elif settings.PROXY_TO_WORKER: generate_worker_js(target, js_target, target_basename) - if embed_memfile(options) and memfile: - delete_file(memfile) - if settings.SPLIT_MODULE: diagnostics.warning('experimental', 'the SPLIT_MODULE setting is experimental and subject to change') do_split_module(wasm_target, options) @@ -2107,7 +2057,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile): @ToolchainProfiler.profile_block('binaryen') -def phase_binaryen(target, options, wasm_target, memfile): +def phase_binaryen(target, options, wasm_target): global final_js logger.debug('using binaryen') # whether we need to emit -g (function name debug info) in the final wasm @@ -2130,7 +2080,7 @@ def phase_binaryen(target, options, wasm_target, memfile): # run wasm-opt if we have work for it: either passes, or if we are using # source maps (which requires some extra processing to keep the source map # but remove DWARF) - passes = get_binaryen_passes(memfile) + passes = get_binaryen_passes() if passes: # if asyncify is used, we will use it in the next stage, and so if it is # the only reason we need intermediate debug info, we can stop keeping it @@ -2147,18 +2097,6 @@ def phase_binaryen(target, options, wasm_target, memfile): debug=intermediate_debug_info) building.save_intermediate(wasm_target, 'byn.wasm') - if memfile: - # we have a separate .mem file. binaryen did not strip any trailing zeros, - # because it's an ABI question as to whether it is valid to do so or not. - # we can do so here, since we make sure to zero out that memory (even in - # the dynamic linking case, our loader zeros it out) - remove_trailing_zeros(memfile) - - # MINIMAL_RUNTIME doesn't use `var memoryInitializer` but instead expects Module['mem'] to - # be loaded before the module. See src/postamble_minimal.js. - if not settings.MINIMAL_RUNTIME: - phase_memory_initializer(memfile) - if settings.EVAL_CTORS: with ToolchainProfiler.profile_block('eval_ctors'): building.eval_ctors(final_js, wasm_target, debug_info=intermediate_debug_info) @@ -2424,7 +2362,7 @@ def module_export_name_substitution(): def generate_traditional_runtime_html(target, options, js_target, target_basename, - wasm_target, memfile): + wasm_target): script = ScriptSource() if settings.EXPORT_NAME != 'Module' and options.shell_path == DEFAULT_SHELL_HTML: @@ -2468,19 +2406,6 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam script.src = base_js_target if not settings.SINGLE_FILE: - if memfile and not settings.MINIMAL_RUNTIME: - # start to load the memory init file in the HTML, in parallel with the JS - script.un_src() - script.inline = (''' - var memoryInitializer = '%s'; - memoryInitializer = Module['locateFile'] ? Module['locateFile'](memoryInitializer, '') : memoryInitializer; - Module['memoryInitializerRequestURL'] = memoryInitializer; - var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest(); - meminitXHR.open('GET', memoryInitializer, true); - meminitXHR.responseType = 'arraybuffer'; - meminitXHR.send(null); -''' % get_subresource_location(memfile)) + script.inline - if not settings.WASM_ASYNC_COMPILATION: # We need to load the wasm file before anything else, since it # has be synchronously ready. @@ -2577,15 +2502,13 @@ def minify_html(filename): logger.debug(f'HTML minification took {elapsed_time:.2f} seconds, and shrunk size of {filename} from {size_before} to {size_after} bytes, delta={delta} ({delta * 100.0 / size_before:+.2f}%)') -def generate_html(target, options, js_target, target_basename, - wasm_target, memfile): +def generate_html(target, options, js_target, target_basename, wasm_target): logger.debug('generating HTML') if settings.MINIMAL_RUNTIME: generate_minimal_runtime_html(target, options, js_target, target_basename) else: - generate_traditional_runtime_html(target, options, js_target, target_basename, - wasm_target, memfile) + generate_traditional_runtime_html(target, options, js_target, target_basename, wasm_target) if settings.MINIFY_HTML and (settings.OPT_LEVEL >= 1 or settings.SHRINK_LEVEL >= 1): minify_html(target) diff --git a/tools/minimal_runtime_shell.py b/tools/minimal_runtime_shell.py index 7fd0716e5fa3..8afddc5c531b 100644 --- a/tools/minimal_runtime_shell.py +++ b/tools/minimal_runtime_shell.py @@ -45,14 +45,6 @@ def generate_minimal_runtime_load_statement(target_basename): files_to_load = ["script('%s')" % (target_basename + '.js')] # Main JS file always in first entry - # Download separate memory initializer file .mem - if not settings.MEM_INIT_IN_WASM: - if settings.MODULARIZE: - modularize_imports += ['mem: r[%d]' % len(files_to_load)] - else: - then_statements += ["%s.mem = r[%d];" % (settings.EXPORT_NAME, len(files_to_load))] - files_to_load += ["binary('%s')" % (target_basename + '.mem')] - # Download .wasm file if (settings.WASM == 1 and settings.WASM2JS == 0) or not download_wasm: if settings.MODULARIZE: