diff --git a/src/audio_worklet.js b/src/audio_worklet.js index 8114b2e8a4fae..2745b542afe05 100644 --- a/src/audio_worklet.js +++ b/src/audio_worklet.js @@ -12,10 +12,6 @@ // the node constructor's "processorOptions" field, we can share the necessary // bootstrap information from the main thread to the AudioWorkletGlobalScope. -#if MINIMAL_RUNTIME -var instantiatePromise; -#endif - if (ENVIRONMENT_IS_AUDIO_WORKLET) { #if AUDIO_WORKLET_SUPPORT_AUDIO_PARAMS diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 7e768f342209a..be55c75d58154 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -195,13 +195,6 @@ var id; */ var moduleArg; -/** - * Used in MODULARIZE mode. - * We need to access this after the code we pass to closure so from closure's - * POV this is "extern". - */ -var moduleRtn; - /** * This was removed from upstream closure compiler in * https://github.com/google/closure-compiler/commit/f83322c1b. diff --git a/src/lib/libcore.js b/src/lib/libcore.js index f11d16b4c02e9..e12adf857b47f 100644 --- a/src/lib/libcore.js +++ b/src/lib/libcore.js @@ -154,9 +154,6 @@ addToLibrary({ // if exit() was called explicitly, warn the user if the runtime isn't actually being shut down if (keepRuntimeAlive() && !implicit) { var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`; -#if MODULARIZE - readyPromiseReject?.(msg); -#endif // MODULARIZE err(msg); } #endif // ASSERTIONS diff --git a/src/modularize.js b/src/modularize.js index 9b4b99e6265cd..5abbeac466c11 100644 --- a/src/modularize.js +++ b/src/modularize.js @@ -29,22 +29,18 @@ var {{{ EXPORT_NAME }}} = (() => { var _scriptName = globalThis.document?.currentScript?.src; #endif return async function(moduleArg = {}) { - var moduleRtn; - "<<< INNER_JS_CODE >>>" - return moduleRtn; + return Module; }; })(); #else // When targeting node and ES6 we use `await import ..` in the generated code // so the outer function needs to be marked as async. async function {{{ EXPORT_NAME }}}(moduleArg = {}) { - var moduleRtn; - "<<< INNER_JS_CODE >>>" - return moduleRtn; + return Module; } #endif diff --git a/src/parseTools.mjs b/src/parseTools.mjs index 54c33952b2b90..ba7c0d1ab2af6 100644 --- a/src/parseTools.mjs +++ b/src/parseTools.mjs @@ -41,10 +41,30 @@ export function processMacros(text, filename) { // `[\s\S]` works like `.` but include newline. pushCurrentFile(filename); try { - return text.replace(/{{{([\s\S]+?)}}}/g, (_, str) => { + text = text.replace(/{{{([\s\S]+?)}}}/g, (_, str) => { const ret = runInMacroContext(str, {filename: filename}); return ret?.toString() ?? ''; }); + // Do special keyword replacement after macro processing, so that + // macros can generate keywords (easier to read preprocessed code). + if (EXPORT_ES6) { + // `eval`, Terser and Closure don't support module syntax; to allow it, + // we need to temporarily replace `import.meta` and `await import` usages + // with placeholders during preprocess phase, and back after all the other ops. + // See also: `phase_final_emitting` in emcc.py. + text = text + .replace(/\bimport\.meta\b/g, 'EMSCRIPTEN$IMPORT$META') + .replace(/\bawait import\b/g, 'EMSCRIPTEN$AWAIT$IMPORT'); + } + if (MODULARIZE) { + // Same for out use of "top-level-await" which is not actually top level + // in the case of MODULARIZE. + text = text.replace(/\bawait createWasm\(\)/g, 'EMSCRIPTEN$AWAIT(createWasm())'); + text = text.replace(/\bawait run\(\)/g, 'EMSCRIPTEN$AWAIT(run())'); + text = text.replace(/\bawait instantiatePromise\b/g, 'EMSCRIPTEN$AWAIT(instantiatePromise)'); + text = text.replace(/\bawait init\(\)/g, 'EMSCRIPTEN$AWAIT(init())'); + } + return text; } finally { popCurrentFile(); } @@ -73,20 +93,6 @@ function findIncludeFile(filename, currentDir) { // Also handles #include x.js (similar to C #include ) export function preprocess(filename) { let text = readFile(filename); - if (EXPORT_ES6) { - // `eval`, Terser and Closure don't support module syntax; to allow it, - // we need to temporarily replace `import.meta` and `await import` usages - // with placeholders during preprocess phase, and back after all the other ops. - // See also: `phase_final_emitting` in emcc.py. - text = text - .replace(/\bimport\.meta\b/g, 'EMSCRIPTEN$IMPORT$META') - .replace(/\bawait import\b/g, 'EMSCRIPTEN$AWAIT$IMPORT'); - } - if (MODULARIZE) { - // Same for out use of "top-level-await" which is not actually top level - // in the case of MODULARIZE. - text = text.replace(/\bawait createWasm\(\)/g, 'EMSCRIPTEN$AWAIT(createWasm())'); - } // Remove windows line endings, if any text = text.replace(/\r\n/g, '\n'); diff --git a/src/postamble.js b/src/postamble.js index 37a06dc690940..f33dd0baaf021 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -114,27 +114,26 @@ function stackCheckInit() { } #endif -#if MAIN_READS_PARAMS -function run(args = programArgs) { -#else -function run() { -#endif +{{{ asyncIf(MODULARIZE) }}}function run({{{ MAIN_READS_PARAMS ? 'args = programArgs' : '' }}}) { #if '$runDependencies' in addedLibraryItems if (runDependencies > 0) { #if RUNTIME_DEBUG dbg('run() called, but dependencies remain, so not running'); #endif +#if MODULARIZE + await new Promise((resolve) => { + dependenciesFulfilled = resolve; + }); +#else dependenciesFulfilled = run; return; +#endif } #endif #if PTHREADS || WASM_WORKERS if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) { -#if MODULARIZE - readyPromiseResolve?.(Module); -#endif initRuntime(); return; } @@ -152,8 +151,14 @@ function run() { #if RUNTIME_DEBUG dbg('run() called, but dependencies remain, so not running'); #endif +#if MODULARIZE + await new Promise((resolve) => { + dependenciesFulfilled = resolve; + }); +#else dependenciesFulfilled = run; return; +#endif } #endif @@ -174,9 +179,6 @@ function run() { preMain(); #endif -#if MODULARIZE - readyPromiseResolve?.(Module); -#endif #if expectToReceiveOnModule('onRuntimeInitialized') Module['onRuntimeInitialized']?.(); #if ASSERTIONS @@ -203,10 +205,20 @@ function run() { #if expectToReceiveOnModule('setStatus') if (Module['setStatus']) { Module['setStatus']('Running...'); +#if MODULARIZE + await new Promise((resolve) => { + setTimeout(() => { + setTimeout(() => Module['setStatus'](''), 1); + doRun(); + resolve(); + }, 1); + }); +#else setTimeout(() => { setTimeout(() => Module['setStatus'](''), 1); doRun(); }, 1); +#endif } else #endif { @@ -297,13 +309,12 @@ export default async function init(moduleArg = {}) { #endif updateMemoryViews(); #if DYNCALLS && '$dynCalls' in addedLibraryItems - assignDynCalls(); #endif #else wasmExports = await createWasm(); #endif - run(); + await run(); } #if ENVIRONMENT_MAY_BE_NODE @@ -315,7 +326,7 @@ if (ENVIRONMENT_IS_NODE ) { const url = await import('node:url'); - const isMainModule = url.pathToFileURL(process.argv[1]).href === import.meta.url; + const isMainModule = process.argv[1] && url.pathToFileURL(process.argv[1]).href === import.meta.url; if (isMainModule) await init(); } #endif @@ -335,23 +346,17 @@ if ({{{ ENVIRONMENT_IS_MAIN_THREAD() }}}) { // Worker threads call this once they receive the module via postMessage #endif -#if WASM_ASYNC_COMPILATION - -#if MODULARIZE -// In modularize mode the generated code is within a factory function so we -// can use await here (since it's not top-level-await). -wasmExports = await createWasm(); -#else +#if !MODULARIZE && WASM_ASYNC_COMPILATION // With async instantation wasmExports is assigned asynchronously when the // instance is received. createWasm(); -#endif - #else -wasmExports = createWasm(); +// In modularize mode the generated code is within a factory function so we +// can use await here (since it's not top-level-await). +wasmExports = {{{ awaitIf(MODULARIZE && WASM_ASYNC_COMPILATION) }}}createWasm(); #endif -run(); +{{{ awaitIf(MODULARIZE) }}}run(); #if WASM_WORKERS || PTHREADS } diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 4396fedf09e84..bf8b65b7af6ef 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -149,6 +149,10 @@ function initRuntime(wasmExports) { // Initialize wasm (asynchronous) +#if MODULARIZE || AUDIO_WORKLET +var instantiatePromise; +#endif + #if SINGLE_FILE && SINGLE_FILE_BINARY_ENCODE && !WASM2JS Module['wasm'] = binaryDecode("<<< WASM_BINARY_DATA >>>"); #elif SINGLE_FILE && WASM == 1 && !WASM2JS @@ -198,7 +202,7 @@ const moduleUrl = `ENVIRONMENT_IS_AUDIO_WORKLET ? '${TARGET_BASENAME}.wasm' : ne // precompiled WebAssembly Module. assert(WebAssembly.instantiateStreaming || Module['wasm'], 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM'); #endif -#if AUDIO_WORKLET +#if MODULARIZE || AUDIO_WORKLET instantiatePromise = #endif (WebAssembly.instantiateStreaming @@ -209,7 +213,7 @@ instantiatePromise = ? WebAssembly.instantiateStreaming(fetch({{{ moduleUrl }}}), imports) : WebAssembly.instantiate(Module['wasm'], imports)).then((output) => { #else -#if AUDIO_WORKLET +#if MODULARIZE || AUDIO_WORKLET instantiatePromise = #endif WebAssembly.instantiateStreaming(fetch({{{ moduleUrl }}}), imports).then((output) => { @@ -228,7 +232,7 @@ assert(Module['wasm'], 'Must load WebAssembly Module in to variable Module.wasm // Add missingProperties supression here because closure compiler doesn't know that // WebAssembly.instantiate is polymorphic in its return value. -#if AUDIO_WORKLET +#if MODULARIZE || AUDIO_WORKLET instantiatePromise = #endif WebAssembly.instantiate(Module['wasm'], imports).then(/** @suppress {missingProperties} */ (output) => { @@ -303,7 +307,7 @@ null; PThread.loadWasmModuleToAllWorkers(); #endif -{{{ waitOnStartupPromisesAndEmitReady(); }}} + return {{{ waitOnStartupPromisesAndEmitReady(); }}} } @@ -334,3 +338,7 @@ null; // When running in a background thread we delay module loading until we have {{{ runIfMainThread('loadModule();') }}} #endif + +#if MODULARIZE +await instantiatePromise; +#endif diff --git a/src/postamble_modularize.js b/src/postamble_modularize.js index 1ba64faad2955..ab2b4c0658b1f 100644 --- a/src/postamble_modularize.js +++ b/src/postamble_modularize.js @@ -1,18 +1,5 @@ // In MODULARIZE mode we wrap the generated code in a factory function // and return either the Module itself, or a promise of the module. -// -// We assign to the `moduleRtn` global here and configure closure to see -// this as an extern so it won't get minified. - -if (runtimeInitialized) { - moduleRtn = Module; -} else { - // Set up the promise that indicates the Module is initialized - moduleRtn = new Promise((resolve, reject) => { - readyPromiseResolve = resolve; - readyPromiseReject = reject; - }); -} #if ASSERTIONS // Assertion for attempting to access module properties on the incoming diff --git a/src/preamble.js b/src/preamble.js index b039a508fac0a..48964d54aed40 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -298,9 +298,6 @@ function abort(what) { /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); -#if MODULARIZE - readyPromiseReject?.(e); -#endif // Throw the error whether or not MODULARIZE is set because abort is used // in code paths apart from instantiation where an exception is expected // to be thrown when abort is called. diff --git a/src/runtime_common.js b/src/runtime_common.js index e4818c0dc13bc..3d7ea7d8d75aa 100644 --- a/src/runtime_common.js +++ b/src/runtime_common.js @@ -31,10 +31,6 @@ function growMemViews() { #include "binaryDecode.js" #endif -#if MODULARIZE -var readyPromiseResolve, readyPromiseReject; -#endif - #if (PTHREADS || WASM_WORKERS) && (ENVIRONMENT_MAY_BE_NODE && !WASM_ESM_INTEGRATION) if (ENVIRONMENT_IS_NODE && {{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) { // Create as web-worker-like an environment as we can. diff --git a/src/shell_minimal.js b/src/shell_minimal.js index 0e71500ef2404..8ddc5c2d8a70a 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -119,9 +119,6 @@ var err = (...args) => console.error(...args); // compilation is ready. In that callback, call the function run() to start // the program. function ready() { -#if MODULARIZE - readyPromiseResolve?.(Module); -#endif // MODULARIZE #if INVOKE_RUN && HAS_MAIN {{{ runIfMainThread("run();") }}} #elif ASSERTIONS diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index 94166f5774a5a..300d33ef23f8e 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -1,4 +1,4 @@ -var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.WorkerGlobalScope, t = !!globalThis.AudioWorkletGlobalScope, u = globalThis.name == "em-ww" || t, v, A, K, F, H, J, x, W, O, G, E, D, X, C, Z; +var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.WorkerGlobalScope, t = !!globalThis.AudioWorkletGlobalScope, u = globalThis.name == "em-ww" || t, v, K, E, G, J, x, W, P, F, D, C, X, A, Z, H; function w(a) { v = a; @@ -21,7 +21,7 @@ if (t) { constructor(d) { super(); d = d.processorOptions; - this.A = C.get(d.A); + this.A = A.get(d.A); this.B = d.B; this.u = d.u; this.v = this.u * 4; @@ -29,8 +29,8 @@ if (t) { this.J(); } J() { - for (var d = D(), g = E(this.C.length * this.v) >> 2, f = this.C.length - 1; f >= 0; f--) this.C[f] = F.subarray(g, g += this.u); - G(d); + for (var d = C(), g = D(this.C.length * this.v) >> 2, f = this.C.length - 1; f >= 0; f--) this.C[f] = E.subarray(g, g += this.u); + F(d); } static get parameterDescriptors() { return c; @@ -42,27 +42,27 @@ if (t) { var I = 0; for (e of g) I += e.length; p += I * this.v; - var P = 0; - for (e in f) ++P, h += 8, p += f[e].byteLength; - var Y = D(), B = h + p + 15 & -16; - h = E(B); + var O = 0; + for (e in f) ++O, h += 8, p += f[e].byteLength; + var Y = C(), B = h + p + 15 & -16; + h = D(B); p = h + (B - p); B = h; for (e of d) { - H[h >> 2] = e.length; - H[h + 4 >> 2] = this.u; - H[h + 8 >> 2] = p; + G[h >> 2] = e.length; + G[h + 4 >> 2] = this.u; + G[h + 8 >> 2] = p; h += 12; - for (q of e) F.set(q, p >> 2), p += this.v; + for (q of e) E.set(q, p >> 2), p += this.v; } d = h; - for (e = 0; q = f[e++]; ) H[h >> 2] = q.length, H[h + 4 >> 2] = p, h += 8, F.set(q, p >> 2), + for (e = 0; q = f[e++]; ) G[h >> 2] = q.length, G[h + 4 >> 2] = p, h += 8, E.set(q, p >> 2), p += q.length * 4; f = h; - for (e of g) H[h >> 2] = e.length, H[h + 4 >> 2] = this.u, H[h + 8 >> 2] = p, h += 12, + for (e of g) G[h >> 2] = e.length, G[h + 4 >> 2] = this.u, G[h + 8 >> 2] = p, h += 12, p += this.v * e.length; - if (l = this.A(l, B, n, f, P, d, this.B)) for (e of g) for (q of e) q.set(this.C[--I]); - G(Y); + if (l = this.A(l, B, n, f, O, d, this.B)) for (e of g) for (q of e) q.set(this.C[--I]); + F(Y); return !!l; } } @@ -79,12 +79,12 @@ if (t) { } registerProcessor("em-bootstrap", b); port.onmessage = async c => { - await A; + await H; c = c.data; c._boot ? w(c) : c._wpn ? (registerProcessor(c._wpn, a(c.K)), port.postMessage({ _wsc: c.A, D: [ c.L, 1, c.B ] - })) : c._wsc && C.get(c._wsc)(...c.D); + })) : c._wsc && A.get(c._wsc)(...c.D); }; } @@ -92,8 +92,8 @@ function y() { var a = x.buffer; J = new Uint8Array(a); K = new Int32Array(a); - H = new Uint32Array(a); - F = new Float32Array(a); + G = new Uint32Array(a); + E = new Float32Array(a); } u || (x = m.mem || new WebAssembly.Memory({ @@ -105,19 +105,19 @@ u || (x = m.mem || new WebAssembly.Memory({ var L = [], M = a => { a = a.data; var b = a._wsc; - b && C.get(b)(...a.x); + b && A.get(b)(...a.x); }, N = a => { L.push(a); }, aa = () => { - O(0, !r && !t, !u, r && !t); + P(0, !r && !t, !u, r && !t); }, ba = a => { a = a.data; var b = a._wsc; - b && C.get(b)(...a.D); + b && A.get(b)(...a.D); }, ca = (a, b, c, k, d, g, f) => { var l = Q[b], n = l.audioWorklet; d = () => { - C.get(g)(b, 0, f); + A.get(g)(b, 0, f); }; if (!n) return d(); n.addModule(m.js).then((() => { @@ -139,7 +139,7 @@ var L = [], M = a => { G: k }); n.port.onmessage = ba; - C.get(g)(b, 1, f); + A.get(g)(b, 1, f); })).catch(d); }, da = (a, b, c, k) => { b = Q[b]; @@ -161,12 +161,12 @@ var L = [], M = a => { return k; }, ea = a => { if (a) { - var b = H[a >> 2]; + var b = G[a >> 2]; b = (b ? T(b) : "") || void 0; var c = K[a + 8 >> 2]; a = { latencyHint: b, - sampleRate: H[a + 4 >> 2] || void 0, + sampleRate: G[a + 4 >> 2] || void 0, O: c < 0 ? "hardware" : c || "default" }; } else a = void 0; @@ -176,17 +176,17 @@ var L = [], M = a => { }, fa = (a, b, c, k, d) => { var g = c ? K[c + 4 >> 2] : 0; if (c) { - var f = K[c >> 2], l = H[c + 8 >> 2], n = g; + var f = K[c >> 2], l = G[c + 8 >> 2], n = g; if (l) { l >>= 2; - for (var e = []; n--; ) e.push(H[l++]); + for (var e = []; n--; ) e.push(G[l++]); l = e; } else l = void 0; c = { numberOfInputs: f, numberOfOutputs: g, outputChannelCount: l, - channelCount: H[c + 12 >> 2] || void 0, + channelCount: G[c + 12 >> 2] || void 0, channelCountMode: [ , "clamped-max", "explicit" ][K[c + 16 >> 2]], channelInterpretation: [ , "discrete" ][K[c + 20 >> 2]], processorOptions: { @@ -200,13 +200,13 @@ var L = [], M = a => { Q[++R] = a; return R; }, ha = (a, b, c, k) => { - var d = (d = H[b >> 2]) ? T(d) : "", g = K[b + 4 >> 2]; - b = H[b + 8 >> 2]; + var d = (d = G[b >> 2]) ? T(d) : "", g = K[b + 4 >> 2]; + b = G[b + 8 >> 2]; for (var f = [], l = 0; g--; ) f.push({ name: l++, - defaultValue: F[b >> 2], - minValue: F[b + 4 >> 2], - maxValue: F[b + 8 >> 2], + defaultValue: E[b >> 2], + minValue: E[b + 4 >> 2], + maxValue: E[b + 8 >> 2], automationRate: (K[b + 12 >> 2] ? "k" : "a") + "-rate" }), b += 16; Q[a].audioWorklet.port.postMessage({ @@ -247,17 +247,17 @@ function z() { a: x, f: la }; - A = WebAssembly.instantiate(m.wasm, { + H = WebAssembly.instantiate(m.wasm, { a: Z }).then((a => { a = (a.instance || a).exports; W = a.n; - O = a.p; - G = a.q; - E = a.r; - D = a.s; + P = a.p; + F = a.q; + D = a.r; + C = a.s; X = a.t; - C = a.o; + A = a.o; u ? (X(v.N, v.M, v.G), t || (removeEventListener("message", N), L = L.forEach(M), addEventListener("message", M))) : a.m(); u || W(); diff --git a/test/codesize/test_codesize_minimal_esm.json b/test/codesize/test_codesize_minimal_esm.json index 29f51dee59ffc..7f2188ceb4481 100644 --- a/test/codesize/test_codesize_minimal_esm.json +++ b/test/codesize/test_codesize_minimal_esm.json @@ -1,10 +1,10 @@ { - "a.out.js": 2446, - "a.out.js.gz": 1176, + "a.out.js": 2393, + "a.out.js.gz": 1128, "a.out.nodebug.wasm": 75, "a.out.nodebug.wasm.gz": 87, - "total": 2521, - "total_gz": 1263, + "total": 2468, + "total_gz": 1215, "sent": [], "imports": [], "exports": [ diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 6e3bea28db86c..e0ed5b30865d2 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -1,10 +1,10 @@ { "a.out.js": 7012, "a.out.js.gz": 3472, - "a.out.nodebug.wasm": 19063, - "a.out.nodebug.wasm.gz": 8803, - "total": 26075, - "total_gz": 12275, + "a.out.nodebug.wasm": 19069, + "a.out.nodebug.wasm.gz": 8800, + "total": 26081, + "total_gz": 12272, "sent": [ "a (memory)", "b (exit)", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index ee49d5c0ce8fb..a416d89785218 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -1,10 +1,10 @@ { "a.out.js": 7420, "a.out.js.gz": 3672, - "a.out.nodebug.wasm": 19064, - "a.out.nodebug.wasm.gz": 8804, - "total": 26484, - "total_gz": 12476, + "a.out.nodebug.wasm": 19070, + "a.out.nodebug.wasm.gz": 8801, + "total": 26490, + "total_gz": 12473, "sent": [ "a (memory)", "b (exit)", diff --git a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json index 92e9aa7db4db6..f2789f2a8f778 100644 --- a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json +++ b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json @@ -2,9 +2,9 @@ "a.html": 515, "a.html.gz": 355, "a.js": 4647, - "a.js.gz": 2380, + "a.js.gz": 2381, "a.wasm": 11237, "a.wasm.gz": 6116, "total": 16399, - "total_gz": 8851 + "total_gz": 8852 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm.json b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm.json index 6284690417b2d..b796ae2e3afb9 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 450, "a.html.gz": 318, - "a.js": 4437, - "a.js.gz": 2284, + "a.js": 4398, + "a.js.gz": 2259, "a.wasm": 8313, "a.wasm.gz": 5646, - "total": 13200, - "total_gz": 8248 + "total": 13161, + "total_gz": 8223 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm2js.json b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm2js.json index 8755f9db6a7f9..08ef9b5c54814 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm2js.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm2js.json @@ -1,8 +1,8 @@ { "a.html": 342, "a.html.gz": 252, - "a.js": 18230, - "a.js.gz": 9837, - "total": 18572, - "total_gz": 10089 + "a.js": 18192, + "a.js.gz": 9813, + "total": 18534, + "total_gz": 10065 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm_singlefile.json b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm_singlefile.json index 25ecff3efe132..57b149f07a2dc 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm_singlefile.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_webgl2_wasm_singlefile.json @@ -1,4 +1,4 @@ { - "a.html": 15046, - "a.html.gz": 9008 + "a.html": 15015, + "a.html.gz": 8990 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm.json b/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm.json index 8fa57fae94f50..9dc6d3a08181b 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 450, "a.html.gz": 318, - "a.js": 3975, - "a.js.gz": 2121, + "a.js": 3936, + "a.js.gz": 2095, "a.wasm": 8313, "a.wasm.gz": 5646, - "total": 12738, - "total_gz": 8085 + "total": 12699, + "total_gz": 8059 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm2js.json b/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm2js.json index 752b7210984f5..88b024fee1321 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm2js.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_webgl_wasm2js.json @@ -1,8 +1,8 @@ { "a.html": 342, "a.html.gz": 252, - "a.js": 17756, - "a.js.gz": 9673, - "total": 18098, - "total_gz": 9925 + "a.js": 17718, + "a.js.gz": 9647, + "total": 18060, + "total_gz": 9899 } diff --git a/test/test_other.py b/test/test_other.py index c90480d7bc4c2..2b428c562d467 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6137,6 +6137,28 @@ def test_modularize_run_dependency(self): self.emcc('hello_world.c', ['-o', 'hello_world.mjs', '-sEXPORT_ES6', '-sMODULARIZE', '-sWASM_ASYNC_COMPILATION=0', '--pre-js=pre.js']) self.assertContained('add-dep\nremove-dep\nHello, world!\ngot module\n', self.run_js('run.mjs')) + def test_modularize_instance_run_dependency(self): + # Ensure that dependencies are fulfilled before the MODULARIZE=instance ready promise is resolved. + create_file('pre.js', ''' + Module.preRun = () => { + dbg("add-dep"); + addRunDependency("my-dep"); + setTimeout(() => { dbg("remove-dep"); removeRunDependency("my-dep"); }, 100); + } + ''') + self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$addRunDependency,$removeRunDependency') + + create_file('run.mjs', ''' + import init from './hello_world.mjs'; + await init(); + console.log('got module'); + ''') + + self.emcc('hello_world.c', ['-o', 'hello_world.mjs', '-sMODULARIZE=instance', '-Wno-experimental', '--pre-js=pre.js']) + + expected = 'add-dep\nremove-dep\nHello, world!\ngot module\n' + self.assertContained(expected, self.run_js('run.mjs')) + def test_modularize_instantiation_error(self): self.run_process([EMCC, test_file('hello_world.c'), '-o', 'out.mjs'] + self.get_cflags()) create_file('run.mjs', ''' diff --git a/tools/building.py b/tools/building.py index b032ccf96fb9e..ddef24e1e5d70 100644 --- a/tools/building.py +++ b/tools/building.py @@ -540,6 +540,12 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None): # should not minify these symbol names. CLOSURE_EXTERNS = [path_from_root('src/closure-externs/closure-externs.js')] + if settings.MODULARIZE: + module_extern_file = shared.get_temp_files().get('.js', prefix='emcc_modularize_extern_') + module_extern_file.write(b'/** @suppress {duplicate} */\nvar Module;\n') + module_extern_file.close() + CLOSURE_EXTERNS += [module_extern_file.name] + if settings.MODULARIZE and settings.ENVIRONMENT_MAY_BE_WEB and not settings.EXPORT_ES6: CLOSURE_EXTERNS += [path_from_root('src/closure-externs/modularize-externs.js')] diff --git a/tools/link.py b/tools/link.py index b4a575fe1ec30..7e438b958f806 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2150,7 +2150,7 @@ def phase_final_emitting(options, target, js_target, wasm_target): if settings.MODULARIZE and settings.MODULARIZE != 'instance': modularize() - elif settings.USE_CLOSURE_COMPILER: + elif settings.USE_CLOSURE_COMPILER and not settings.MODULARIZE: module_export_name_substitution() # Run a final optimization pass to clean up items that were not possible to