From f30e444758771246d7de436fbb261321a6aca4e0 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Mon, 16 Mar 2020 01:13:49 -0400 Subject: [PATCH 01/34] Changes modularized build to promise-based API This removes the `Module#then` function and replaces it with a proper Promise being returned from the initialization function. Fixes #5820 --- emcc.py | 4 +++- src/postamble.js | 47 +++++++++++++------------------------------ tests/test_browser.py | 41 +++++++++++++++++-------------------- 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/emcc.py b/emcc.py index 55ed7316c158e..aad97ec5d2670 100755 --- a/emcc.py +++ b/emcc.py @@ -3355,11 +3355,13 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { + return new Promise((returned_promise_resolve, returned_promise_reject) => { + %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; %(src)s - return %(exports_object)s + }); } ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, diff --git a/src/postamble.js b/src/postamble.js index bf7f53ff0f550..d39790ca0bca0 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -63,7 +63,7 @@ if (memoryInitializer) { }; var doBrowserLoad = function() { readAsync(memoryInitializer, applyMemoryInitializer, function() { - throw 'could not load memory initializer ' + memoryInitializer; + returned_promise_reject(new Error('could not load memory initializer ' + memoryInitializer)); }); }; #if SUPPORT_BASE64_EMBEDDING @@ -116,36 +116,6 @@ if (memoryInitializer) { var calledRun; -#if MODULARIZE -#if MODULARIZE_INSTANCE == 0 -// Modularize mode returns a function, which can be called to -// create instances. The instances provide a then() method, -// must like a Promise, that receives a callback. The callback -// is called when the module is ready to run, with the module -// as a parameter. (Like a Promise, it also returns the module -// so you can use the output of .then(..)). -Module['then'] = function(func) { - // We may already be ready to run code at this time. if - // so, just queue a call to the callback. - if (calledRun) { - func(Module); - } else { - // we are not ready to call then() yet. we must call it - // at the same time we would call onRuntimeInitialized. -#if ASSERTIONS && !expectToReceiveOnModule('onRuntimeInitialized') - abort('.then() requires adding onRuntimeInitialized to INCOMING_MODULE_JS_API'); -#endif - var old = Module['onRuntimeInitialized']; - Module['onRuntimeInitialized'] = function() { - if (old) old(); - func(Module); - }; - } - return Module; -}; -#endif -#endif - /** * @constructor * @this {ExitStatus} @@ -314,6 +284,9 @@ function run(args) { preMain(); +#if MODULARIZE + returned_promise_resolve(Module); +#endif #if expectToReceiveOnModule('onRuntimeInitialized') if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); #endif @@ -424,9 +397,17 @@ function exit(status, implicit) { // if exit() was called, we may warn the user if the runtime isn't actually being shut down if (!implicit) { #if EXIT_RUNTIME == 0 - err('program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'); + var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'; + err(msg); +#if MODULARIZE + returned_promise_reject(msg); +#endif // MODULARIZE #else - err('program exited (with status: ' + status + '), but noExitRuntime is set 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)'); + var msg = 'program exited (with status: ' + status + '), but noExitRuntime is set 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)'; + err(msg); +#if MODULARIZE + returned_promise_reject(msg); +#endif // MODULARIZE #endif // EXIT_RUNTIME } #endif // ASSERTIONS diff --git a/tests/test_browser.py b/tests/test_browser.py index c3d494810e44c..bb421e0c858a3 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3352,39 +3352,36 @@ def test_minimal_runtime_modularize(self): @requires_sync_compilation def test_modularize(self): - for opts in [[], ['-O1'], ['-O2', '-profiling'], ['-O2'], ['-O2', '--closure', '1']]: + for opts in [ + [], + ['-O1'], + ['-O2', '-profiling'], + ['-O2'], + ['-O2', '--closure', '1'] + ]: for args, code in [ - ([], 'Module();'), # defaults + # defaults + ([], ''' + let promise = Module(); + if (!promise instanceof Promise) throw new Error('Return value should be a promise'); + '''), # use EXPORT_NAME (['-s', 'EXPORT_NAME="HelloWorld"'], ''' if (typeof Module !== "undefined") throw "what?!"; // do not pollute the global scope, we are modularized! HelloWorld.noInitialRun = true; // errorneous module capture will load this and cause timeout - HelloWorld(); + let promise = HelloWorld(); + if (!promise instanceof Promise) throw new Error('Return value should be a promise'); '''), # pass in a Module option (which prevents main(), which we then invoke ourselves) (['-s', 'EXPORT_NAME="HelloWorld"'], ''' - var hello = HelloWorld({ noInitialRun: true, onRuntimeInitialized: function() { - setTimeout(function() { hello._main(); }); // must be async, because onRuntimeInitialized may be called synchronously, so |hello| is not yet set! - } }); - '''), - # similar, but without a mem init file, everything is sync and simple - (['-s', 'EXPORT_NAME="HelloWorld"', '--memory-init-file', '0'], ''' - var hello = HelloWorld({ noInitialRun: true}); - hello._main(); - '''), - # use the then() API - (['-s', 'EXPORT_NAME="HelloWorld"'], ''' - HelloWorld({ noInitialRun: true }).then(function(hello) { + HelloWorld({ noInitialRun: true }).then(hello => { hello._main(); }); '''), - # then() API, also note the returned value - (['-s', 'EXPORT_NAME="HelloWorld"'], ''' - var helloOutside = HelloWorld({ noInitialRun: true }).then(function(hello) { - setTimeout(function() { - hello._main(); - if (hello !== helloOutside) throw 'helloOutside has not been set!'; // as we are async, helloOutside must have been set - }); + # Even without a mem init file, everything is async + (['-s', 'EXPORT_NAME="HelloWorld"', '--memory-init-file', '0'], ''' + HelloWorld({ noInitialRun: true }).then(hello => { + hello._main(); }); '''), ]: From b4ec2f4ee1b236bdcc16e0a4c3e335312e10c861 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Mon, 16 Mar 2020 19:28:28 -0400 Subject: [PATCH 02/34] Adds modularized promise functions to externs --- emcc.py | 7 ++++--- src/closure-externs/closure-externs.js | 8 ++++++++ src/postamble.js | 7 ++++++- tests/test_browser.py | 8 ++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/emcc.py b/emcc.py index aad97ec5d2670..6ba58261dd59a 100755 --- a/emcc.py +++ b/emcc.py @@ -3355,13 +3355,14 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { - return new Promise((returned_promise_resolve, returned_promise_reject) => { - + var returned_promise_resolve, returned_promise_reject; + var promise = new Promise((resolve, reject) => (returned_promise_resolve=resolve, returned_promise_reject=reject)); + %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; %(src)s - }); + return promise; } ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index aa452438948be..c51e020a283b0 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -994,3 +994,11 @@ var threadInfoStruct; var selfThreadId; /** @suppress {duplicate} */ var noExitRuntime; + +// These functions are declared in emcc.py but used in postamble.js; we need +// to explicitly tell Closure Compiler about their existence since the +// postamble is optimized independently +/** @type {Function} */ +var returned_promise_resolve; +/** @type {Function} */ +var returned_promise_reject; \ No newline at end of file diff --git a/src/postamble.js b/src/postamble.js index d39790ca0bca0..d003d89ed99b3 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -63,7 +63,12 @@ if (memoryInitializer) { }; var doBrowserLoad = function() { readAsync(memoryInitializer, applyMemoryInitializer, function() { - returned_promise_reject(new Error('could not load memory initializer ' + memoryInitializer)); + var e = new Error('could not load memory initializer ' + memoryInitializer); +#if MODULARIZE + returned_promise_reject(e); +#else + throw e; +#endif }); }; #if SUPPORT_BASE64_EMBEDDING diff --git a/tests/test_browser.py b/tests/test_browser.py index bb421e0c858a3..d0d9eb8e40672 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3353,10 +3353,10 @@ def test_minimal_runtime_modularize(self): @requires_sync_compilation def test_modularize(self): for opts in [ - [], - ['-O1'], - ['-O2', '-profiling'], - ['-O2'], + [], + ['-O1'], + ['-O2', '-profiling'], + ['-O2'], ['-O2', '--closure', '1'] ]: for args, code in [ From 6f4997a145c029e640e6c1977253d18ad7609918 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Tue, 17 Mar 2020 22:00:14 -0400 Subject: [PATCH 03/34] Changes worker.js to account for promise Also removes exports_object reference from emcc.py. It's probably not correct, but highlights that it's not being used if a promise is always returned. --- emcc.py | 7 +------ src/worker.js | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/emcc.py b/emcc.py index 6ba58261dd59a..9c15bc5e1ef67 100755 --- a/emcc.py +++ b/emcc.py @@ -3349,10 +3349,6 @@ def modularize(): logger.debug('Modularizing, assigning to var ' + shared.Settings.EXPORT_NAME) src = open(final).read() - # TODO: exports object generation for MINIMAL_RUNTIME. As a temp measure, multithreaded MINIMAL_RUNTIME builds export like regular - # runtime does, so that worker.js can see the JS module contents. - exports_object = '{}' if shared.Settings.MINIMAL_RUNTIME and not shared.Settings.USE_PTHREADS else shared.Settings.EXPORT_NAME - src = ''' function(%(EXPORT_NAME)s) { var returned_promise_resolve, returned_promise_reject; @@ -3367,7 +3363,6 @@ def modularize(): ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, 'src': src, - 'exports_object': exports_object } if not shared.Settings.MODULARIZE_INSTANCE: @@ -3408,7 +3403,7 @@ def modularize(): # and the user can decide whether to use Module there or something # else etc.). src = ''' -var %(EXPORT_NAME)s = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); +var initPromise = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, 'src': src diff --git a/src/worker.js b/src/worker.js index 0d11f03380273..7a17bcbdd1ab2 100644 --- a/src/worker.js +++ b/src/worker.js @@ -141,11 +141,11 @@ this.onmessage = function(e) { {{{ makeAsmImportsAccessInPthread('ENVIRONMENT_IS_PTHREAD') }}} = true; #endif +var initPromise; #if MODULARIZE && EXPORT_ES6 - import(e.data.urlOrBlob).then(function({{{ EXPORT_NAME }}}) { - Module = {{{ EXPORT_NAME }}}.default(Module); - postMessage({ 'cmd': 'loaded' }); - }); + initPromise = import(e.data.urlOrBlob).then(function({{{ EXPORT_NAME }}}) { + return {{{ EXPORT_NAME }}}.default(Module); + }) #else if (typeof e.data.urlOrBlob === 'string') { importScripts(e.data.urlOrBlob); @@ -156,18 +156,20 @@ this.onmessage = function(e) { } #if MODULARIZE && !MODULARIZE_INSTANCE #if MINIMAL_RUNTIME - Module = {{{ EXPORT_NAME }}}(imports); + initPromise = {{{ EXPORT_NAME }}}(imports); #else - Module = {{{ EXPORT_NAME }}}(Module); + initPromise = {{{ EXPORT_NAME }}}(Module); #endif #endif -#if !MINIMAL_RUNTIME || !WASM - // MINIMAL_RUNTIME always compiled Wasm (&Wasm2JS) asynchronously, even in pthreads. But - // regular runtime and asm.js are loaded synchronously, so in those cases - // we are now loaded, and can post back to main thread. - postMessage({ 'cmd': 'loaded' }); -#endif +if (initPromise === undefined) { + postMessage({ 'cmd': 'loaded' }); +} else { + initPromise.then(function(mod) { + Module = mod; + postMessage({ 'cmd': 'loaded' }); + }); +} #endif } else if (e.data.cmd === 'objectTransfer') { From fc9e049a99f53bf5de4c312ebaed14dbd23f4158 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Thu, 19 Mar 2020 01:44:03 -0400 Subject: [PATCH 04/34] Tries different structure for src/worker.js --- src/worker.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/worker.js b/src/worker.js index 7a17bcbdd1ab2..bfa369fc31919 100644 --- a/src/worker.js +++ b/src/worker.js @@ -108,7 +108,7 @@ this.onmessage = function(e) { #endif #else Module['wasmModule'] = e.data.wasmModule; -#endif +#endif // MINIMAL_RUNTIME {{{ makeAsmImportsAccessInPthread('wasmMemory') }}} = e.data.wasmMemory; @@ -135,17 +135,19 @@ this.onmessage = function(e) { } #endif -#endif +#endif // WASM #if !MINIMAL_RUNTIME || MODULARIZE {{{ makeAsmImportsAccessInPthread('ENVIRONMENT_IS_PTHREAD') }}} = true; #endif -var initPromise; #if MODULARIZE && EXPORT_ES6 - initPromise = import(e.data.urlOrBlob).then(function({{{ EXPORT_NAME }}}) { + import(e.data.urlOrBlob).then(function({{{ EXPORT_NAME }}}) { return {{{ EXPORT_NAME }}}.default(Module); - }) + }).then(function(instance) { + Module = instance; + postMessage({ 'cmd': 'loaded' }); + }); #else if (typeof e.data.urlOrBlob === 'string') { importScripts(e.data.urlOrBlob); @@ -156,20 +158,24 @@ var initPromise; } #if MODULARIZE && !MODULARIZE_INSTANCE #if MINIMAL_RUNTIME - initPromise = {{{ EXPORT_NAME }}}(imports); + {{{ EXPORT_NAME }}}(imports).then(function(instance) { + Module = instance; + postMessage({ 'cmd': 'loaded' }); + }); #else - initPromise = {{{ EXPORT_NAME }}}(Module); + {{{ EXPORT_NAME }}}(Module).then(function(instance) { + Module = instance; + postMessage({ 'cmd': 'loaded' }); + }); #endif #endif -if (initPromise === undefined) { - postMessage({ 'cmd': 'loaded' }); -} else { - initPromise.then(function(mod) { - Module = mod; - postMessage({ 'cmd': 'loaded' }); - }); -} +#if !MODULARIZE && (!MINIMAL_RUNTIME || !WASM) + // MINIMAL_RUNTIME always compiled Wasm (&Wasm2JS) asynchronously, even in pthreads. But + // regular runtime and asm.js are loaded synchronously, so in those cases + // we are now loaded, and can post back to main thread. + postMessage({ 'cmd': 'loaded' }); +#endif #endif } else if (e.data.cmd === 'objectTransfer') { From 49ae9d2ea6e729b2f8614ff60b172a32cc7cbc21 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Thu, 19 Mar 2020 01:44:32 -0400 Subject: [PATCH 05/34] Clarifies a comment --- emcc.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/emcc.py b/emcc.py index 9c15bc5e1ef67..9e36d2f56c7f2 100755 --- a/emcc.py +++ b/emcc.py @@ -3397,11 +3397,10 @@ def modularize(): 'src': src } else: - # Create the MODULARIZE_INSTANCE instance - # Note that we notice the global Module object, just like in normal - # non-MODULARIZE mode (while MODULARIZE has the user create the instances, - # and the user can decide whether to use Module there or something - # else etc.). + # Create the promise for the MODULARIZE_INSTANCE instance + # Note that the global, custom-named Module object is passed to the factory + # invocation just like in non-MODULARIZE mode; MODULARIZE code has the user + # creates the instance, leaving it up to them to pass in any Module seed. src = ''' var initPromise = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); ''' % { From af82a9cbaa4722dbae963327b4cf6bc1084e311c Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Thu, 2 Apr 2020 20:37:00 -0400 Subject: [PATCH 06/34] Adds promise handler for MODULARIZE_INSTANCE case in worker --- src/worker.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/worker.js b/src/worker.js index 7d2b1e338757c..ff62e75376b95 100644 --- a/src/worker.js +++ b/src/worker.js @@ -157,7 +157,13 @@ this.onmessage = function(e) { importScripts(objectUrl); URL.revokeObjectURL(objectUrl); } -#if MODULARIZE && !MODULARIZE_INSTANCE +#if MODULARIZE_INSTANCE + initPromise.then(function(instance) { + Module = instance; + postMessage({ 'cmd': 'loaded' }); + }); +#else +#if MODULARIZE #if MINIMAL_RUNTIME {{{ EXPORT_NAME }}}(imports).then(function(instance) { Module = instance; @@ -170,6 +176,7 @@ this.onmessage = function(e) { }); #endif #endif +#endif #if !MODULARIZE && (!MINIMAL_RUNTIME || !WASM) // MINIMAL_RUNTIME always compiled Wasm (&Wasm2JS) asynchronously, even in pthreads. But From b402022009e09678f6420731860e5abafc3b9c87 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Tue, 14 Apr 2020 22:05:15 -0400 Subject: [PATCH 07/34] Adds additional promise resolution in postamble.js Turns out that the pthreads don't execute `run`, so need their own promise resolution. --- emcc.py | 9 +++++---- src/postamble.js | 20 ++++++++++++++------ src/worker.js | 6 +++--- tests/test_browser.py | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/emcc.py b/emcc.py index 08949b505cf20..6fcd7cffdb55c 100755 --- a/emcc.py +++ b/emcc.py @@ -3421,10 +3421,11 @@ def modularize(): 'src': src } else: - # Create the promise for the MODULARIZE_INSTANCE instance - # Note that the global, custom-named Module object is passed to the factory - # invocation just like in non-MODULARIZE mode; MODULARIZE code has the user - # creates the instance, leaving it up to them to pass in any Module seed. + # Create the promise for the MODULARIZE_INSTANCE instance. Note that the + # global, custom-named `Module` object is passed to the factory function + # invocation, just like in non-MODULARIZE mode. This is noticeably + # different than code built with the MODULARIZE option where the user + # specifies any Module seed when calling the factory function themselves. src = ''' var initPromise = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); ''' % { diff --git a/src/postamble.js b/src/postamble.js index e566ceba48ce6..7a58e45e55099 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -278,9 +278,9 @@ function run(args) { #endif preRun(); - + if (runDependencies > 0) return; // a preRun added a dependency, run will be called later - + function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, // or while the async setStatus time below was happening @@ -470,15 +470,23 @@ if (!ENVIRONMENT_IS_PTHREAD) // EXIT_RUNTIME=0 only applies to default behavior #endif #if USE_PTHREADS -if (!ENVIRONMENT_IS_PTHREAD) run(); +if (!ENVIRONMENT_IS_PTHREAD) { + run(); +} else { #if EMBIND -else { // Embind must initialize itself on all threads, as it generates support JS. + // Embind must initialize itself on all threads, as it generates support JS. Module['___embind_register_native_and_builtin_types'](); -} #endif // EMBIND +#if MODULARIZE + // The promise resolve function typically gets called as part of the execution + // of the Module `run`. The pthreads themselves don't execute `run`, so the + // creation promise can be resolved, marking the pthread-Module as initialized. + returned_promise_resolve(Module); +#endif // MODULARIZE +} #else run(); -#endif +#endif // USE_PTHREADS #if BUILD_AS_WORKER diff --git a/src/worker.js b/src/worker.js index ff62e75376b95..d2238eeee561c 100644 --- a/src/worker.js +++ b/src/worker.js @@ -158,19 +158,19 @@ this.onmessage = function(e) { URL.revokeObjectURL(objectUrl); } #if MODULARIZE_INSTANCE - initPromise.then(function(instance) { + initPromise.then((instance) => { Module = instance; postMessage({ 'cmd': 'loaded' }); }); #else #if MODULARIZE #if MINIMAL_RUNTIME - {{{ EXPORT_NAME }}}(imports).then(function(instance) { + {{{ EXPORT_NAME }}}(imports).then((instance) => { Module = instance; postMessage({ 'cmd': 'loaded' }); }); #else - {{{ EXPORT_NAME }}}(Module).then(function(instance) { + {{{ EXPORT_NAME }}}(Module).then((instance) => { Module = instance; postMessage({ 'cmd': 'loaded' }); }); diff --git a/tests/test_browser.py b/tests/test_browser.py index d1f966630b75b..cd7200b14c5e0 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3694,7 +3694,7 @@ def test_pthread_create(self): def test(args): print(args) self.btest(path_from_root('tests', 'pthread', 'test_pthread_create.cpp'), expected='0', args=['-s', 'INITIAL_MEMORY=64MB', '-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=8'] + args) - + print() # new line test([]) test(['-O3']) test(['-s', 'MODULARIZE_INSTANCE=1']) From f20506100b201805e807b584461d4d38e7ce59ce Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Tue, 14 Apr 2020 22:15:24 -0400 Subject: [PATCH 08/34] Removes some whitespace --- src/postamble.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index 7a58e45e55099..28f1af19e6ad2 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -278,9 +278,9 @@ function run(args) { #endif preRun(); - + if (runDependencies > 0) return; // a preRun added a dependency, run will be called later - + function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, // or while the async setStatus time below was happening From 69ba48bde42d9ad98e5e7ad2d5851358e56cc9a9 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Tue, 14 Apr 2020 23:44:42 -0400 Subject: [PATCH 09/34] Changes promise variable name back to EXPORT_NAME --- emcc.py | 2 +- src/worker.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index 3c945d175d55f..ea0e49d3f4a29 100755 --- a/emcc.py +++ b/emcc.py @@ -3454,7 +3454,7 @@ def modularize(): # different than code built with the MODULARIZE option where the user # specifies any Module seed when calling the factory function themselves. src = ''' -var initPromise = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); +var %(EXPORT_NAME)s = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, 'src': src diff --git a/src/worker.js b/src/worker.js index d2238eeee561c..210bf99a42162 100644 --- a/src/worker.js +++ b/src/worker.js @@ -158,7 +158,7 @@ this.onmessage = function(e) { URL.revokeObjectURL(objectUrl); } #if MODULARIZE_INSTANCE - initPromise.then((instance) => { + {{{ EXPORT_NAME }}}.then((instance) => { Module = instance; postMessage({ 'cmd': 'loaded' }); }); From cc890094c2a86567761105f873e17c4b11813be8 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 00:46:52 -0400 Subject: [PATCH 10/34] Adds _promise suffix to the instance promise var Also removes onRuntimeInitialized implicit export in MODULARIZE builds --- emcc.py | 27 +++++++++++++++------------ src/worker.js | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/emcc.py b/emcc.py index ea0e49d3f4a29..2afd44fef6ff0 100755 --- a/emcc.py +++ b/emcc.py @@ -1328,9 +1328,6 @@ def has_c_source(args): if shared.Settings.MODULARIZE: assert not options.proxy_to_worker, '-s MODULARIZE=1 and -s MODULARIZE_INSTANCE=1 are not compatible with --proxy-to-worker (if you want to run in a worker with -s MODULARIZE=1, you likely want to do the worker side setup manually)' - # MODULARIZE's .then() method uses onRuntimeInitialized currently, so make sure - # it is expected to be used. - shared.Settings.INCOMING_MODULE_JS_API += ['onRuntimeInitialized'] if shared.Settings.EMULATE_FUNCTION_POINTER_CASTS: shared.Settings.ALIASING_FUNCTION_POINTERS = 0 @@ -3448,26 +3445,32 @@ def modularize(): 'src': src } else: - # Create the promise for the MODULARIZE_INSTANCE instance. Note that the - # global, custom-named `Module` object is passed to the factory function - # invocation, just like in non-MODULARIZE mode. This is noticeably + promise_variable_suffix = '_promise' + # Create the promise for the MODULARIZE_INSTANCE instance. The name of the + # variable will be `Module_promise` by default. If the EXPORT_NAME option + # is specified, the variable named will be `{EXPORT_NAME}_promise`. + # + # Note that the global, custom-named `Module` object is passed to the + # factory function invocation, just like in non-MODULARIZE mode. This is # different than code built with the MODULARIZE option where the user # specifies any Module seed when calling the factory function themselves. src = ''' -var %(EXPORT_NAME)s = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); +var %(EXPORT_NAME)s%(promise_variable_suffix)s = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {}); ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, - 'src': src + 'src': src, + 'promise_variable_suffix': promise_variable_suffix, } final = final + '.modular.js' with open(final, 'w') as f: f.write(src) - + export_name = shared.Settings.EXPORT_NAME + if (shared.Settings.MODULARIZE_INSTANCE): + export_name += promise_variable_suffix # Export using a UMD style export, or ES6 exports if selected - if shared.Settings.EXPORT_ES6: - f.write('''export default %s;''' % shared.Settings.EXPORT_NAME) + f.write('''export default %s;''' % export_name) elif not shared.Settings.MINIMAL_RUNTIME: f.write('''if (typeof exports === 'object' && typeof module === 'object') module.exports = %(EXPORT_NAME)s; @@ -3476,7 +3479,7 @@ def modularize(): else if (typeof exports === 'object') exports["%(EXPORT_NAME)s"] = %(EXPORT_NAME)s; ''' % { - 'EXPORT_NAME': shared.Settings.EXPORT_NAME + 'EXPORT_NAME': export_name }) save_intermediate('modularized') diff --git a/src/worker.js b/src/worker.js index 210bf99a42162..5b9bdb6afe9ce 100644 --- a/src/worker.js +++ b/src/worker.js @@ -158,7 +158,7 @@ this.onmessage = function(e) { URL.revokeObjectURL(objectUrl); } #if MODULARIZE_INSTANCE - {{{ EXPORT_NAME }}}.then((instance) => { + {{{ EXPORT_NAME }}}_promise.then((instance) => { Module = instance; postMessage({ 'cmd': 'loaded' }); }); From 0ab88411410d8dc86fbc57956bb326a9b44d34b1 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 11:34:18 -0400 Subject: [PATCH 11/34] Adds module promise resolution for MINIMAL_RUNTIME --- src/postamble.js | 5 +++-- src/shell_minimal.js | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index 28f1af19e6ad2..d580dd28aba7e 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -479,8 +479,9 @@ if (!ENVIRONMENT_IS_PTHREAD) { #endif // EMBIND #if MODULARIZE // The promise resolve function typically gets called as part of the execution - // of the Module `run`. The pthreads themselves don't execute `run`, so the - // creation promise can be resolved, marking the pthread-Module as initialized. + // of the Module `run`. The workers/pthreads don't execute `run` here, they + // call `run` in response to a message at a later time, so the creation + // promise can be resolved, marking the pthread-Module as initialized. returned_promise_resolve(Module); #endif // MODULARIZE } diff --git a/src/shell_minimal.js b/src/shell_minimal.js index b722e9bdd8f6e..b48f9c46e84ef 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -131,6 +131,9 @@ function err(text) { // compilation is ready. In that callback, call the function run() to start // the program. function ready() { +#if MODULARIZE + returned_promise_resolve(Module); +#endif // MODULARIZE #if INVOKE_RUN && hasExportedFunction('_main') #if USE_PTHREADS if (!ENVIRONMENT_IS_PTHREAD) { From 30209ebb141ce0c4e9b800ad56cfdd8be26ed797 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 13:40:35 -0400 Subject: [PATCH 12/34] Updates the expected code sizes, adding about 220B --- tests/code_size/hello_webgl2_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm2js.json | 8 ++++---- tests/code_size/hello_webgl_wasm.json | 8 ++++---- tests/code_size/hello_webgl_wasm2js.json | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index 64269e198948b..6cf8a4e1d5e7c 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5123, - "a.js.gz": 2419, + "a.js": 5360, + "a.js.gz": 2494, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16580, - "total_gz": 9716 + "total": 16817, + "total_gz": 9791 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index 0136a6d63f60d..c4c2f68776f92 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23727, - "a.js.gz": 8896, + "a.js": 23964, + "a.js.gz": 8968, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27483, - "total_gz": 11993 + "total": 27720, + "total_gz": 12065 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index 80fc641f1fed5..9a68d78b56db6 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4615, - "a.js.gz": 2248, + "a.js": 4852, + "a.js.gz": 2322, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16072, - "total_gz": 9545 + "total": 16309, + "total_gz": 9619 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index 5cb02e380307a..99aa371fbb364 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23222, - "a.js.gz": 8731, + "a.js": 23459, + "a.js.gz": 8806, "a.mem": 3168, "a.mem.gz": 2711, - "total": 26978, - "total_gz": 11828 + "total": 27215, + "total_gz": 11903 } From b44e3a3257bdd3efdddfb63033297b36c2a74365 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 14:55:35 -0400 Subject: [PATCH 13/34] Removes whitespace --- emcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index 2afd44fef6ff0..c6b28d77dbba3 100755 --- a/emcc.py +++ b/emcc.py @@ -3449,7 +3449,7 @@ def modularize(): # Create the promise for the MODULARIZE_INSTANCE instance. The name of the # variable will be `Module_promise` by default. If the EXPORT_NAME option # is specified, the variable named will be `{EXPORT_NAME}_promise`. - # + # # Note that the global, custom-named `Module` object is passed to the # factory function invocation, just like in non-MODULARIZE mode. This is # different than code built with the MODULARIZE option where the user From 9219dc2a67c9aabde1d932f3ec19bdb113f9d14b Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 16:02:12 -0400 Subject: [PATCH 14/34] Updates code sizes for hello_webgl_fastcomp_wasm --- tests/code_size/hello_webgl_fastcomp_wasm.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index 78b6ff6dc6582..e9d63208a5eb1 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4837, - "a.js.gz": 2361, + "a.js": 5074, + "a.js.gz": 2436, "a.wasm": 7982, - "a.wasm.gz": 4368, - "total": 13382, - "total_gz": 7106 + "a.wasm.gz": 4364, + "total": 13619, + "total_gz": 7177 } From 0f0166bb4f193bcc17c006c423694b0c30d8de95 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 16:09:54 -0400 Subject: [PATCH 15/34] Changes arrow functions to function expressions --- emcc.py | 2 +- src/worker.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emcc.py b/emcc.py index c6b28d77dbba3..d324bd891d7e8 100755 --- a/emcc.py +++ b/emcc.py @@ -3400,7 +3400,7 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { var returned_promise_resolve, returned_promise_reject; - var promise = new Promise((resolve, reject) => (returned_promise_resolve=resolve, returned_promise_reject=reject)); + var promise = new Promise(function(resolve, reject) { returned_promise_resolve=resolve, returned_promise_reject=reject; }); %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; diff --git a/src/worker.js b/src/worker.js index 5b9bdb6afe9ce..b0411fbc2a276 100644 --- a/src/worker.js +++ b/src/worker.js @@ -158,19 +158,19 @@ this.onmessage = function(e) { URL.revokeObjectURL(objectUrl); } #if MODULARIZE_INSTANCE - {{{ EXPORT_NAME }}}_promise.then((instance) => { + {{{ EXPORT_NAME }}}_promise.then(function (instance) { Module = instance; postMessage({ 'cmd': 'loaded' }); }); #else #if MODULARIZE #if MINIMAL_RUNTIME - {{{ EXPORT_NAME }}}(imports).then((instance) => { + {{{ EXPORT_NAME }}}(imports).then(function (instance) { Module = instance; postMessage({ 'cmd': 'loaded' }); }); #else - {{{ EXPORT_NAME }}}(Module).then((instance) => { + {{{ EXPORT_NAME }}}(Module).then(function (instance) { Module = instance; postMessage({ 'cmd': 'loaded' }); }); From 98eadf40012d7df22e60aeac3519aa886e1839e0 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 16:45:06 -0400 Subject: [PATCH 16/34] Updates code sizes for hello_webgl2_fastcomp_wasm --- tests/code_size/hello_webgl2_fastcomp_wasm.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index d1299365cd49d..2185a7c30ac6e 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5344, - "a.js.gz": 2531, + "a.js": 5587, + "a.js.gz": 2607, "a.wasm": 7982, - "a.wasm.gz": 4368, - "total": 13889, - "total_gz": 7276 + "a.wasm.gz": 4362, + "total": 14132, + "total_gz": 7346 } From a7cd5ee3c2f60a4a332e498c885b034720694c8d Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 17:47:23 -0400 Subject: [PATCH 17/34] Updates code sizes for hello_webgl_fastcomp_asmjs --- tests/code_size/hello_webgl_fastcomp_asmjs.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index 866396a65b9d8..1de9c7225e435 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 4868, - "a.js.gz": 2349, + "a.js": 5111, + "a.js.gz": 2421, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9778, "a.asm.js.gz": 3528, - "total": 15547, - "total_gz": 6478 + "total": 15790, + "total_gz": 6550 } From ed0fa51addfe5361b9bc3872bac461a07b5975a9 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 19:12:57 -0400 Subject: [PATCH 18/34] Updates the rest of the fastcomp code sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Got frustrated enough going one-by-one with CI failures to setup the Fastcomp so I could use the EMTEST_REBASELINE flag to automatically update the sizes. Gotta love cloning 2 projects and building an entire compiler from source just to update a few data files 🤡 --- tests/code_size/hello_webgl2_fastcomp_asmjs.json | 12 ++++++------ tests/code_size/hello_webgl2_fastcomp_wasm.json | 6 +++--- tests/code_size/hello_webgl_fastcomp_asmjs.json | 6 +++--- tests/code_size/hello_webgl_fastcomp_wasm.json | 10 +++++----- tests/code_size/random_printf_fastcomp_wasm.json | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/code_size/hello_webgl2_fastcomp_asmjs.json b/tests/code_size/hello_webgl2_fastcomp_asmjs.json index 4023d9145cc32..013584da6f779 100644 --- a/tests/code_size/hello_webgl2_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl2_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5322, - "a.js.gz": 2505, + "a.js": 5565, + "a.js.gz": 2577, "a.mem": 321, "a.mem.gz": 219, - "a.asm.js": 9778, - "a.asm.js.gz": 3528, - "total": 16001, - "total_gz": 6634 + "a.asm.js": 9806, + "a.asm.js.gz": 3516, + "total": 16244, + "total_gz": 6694 } diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index 2185a7c30ac6e..4e01a1c3cc248 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 377, "a.js": 5587, "a.js.gz": 2607, - "a.wasm": 7982, - "a.wasm.gz": 4362, + "a.wasm": 7985, + "a.wasm.gz": 4411, "total": 14132, - "total_gz": 7346 + "total_gz": 7395 } diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index 1de9c7225e435..edc15c4c218ef 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -5,8 +5,8 @@ "a.js.gz": 2421, "a.mem": 321, "a.mem.gz": 219, - "a.asm.js": 9778, - "a.asm.js.gz": 3528, + "a.asm.js": 9806, + "a.asm.js.gz": 3516, "total": 15790, - "total_gz": 6550 + "total_gz": 6538 } diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index e9d63208a5eb1..50bbb77822330 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5074, - "a.js.gz": 2436, - "a.wasm": 7982, - "a.wasm.gz": 4364, + "a.js": 5080, + "a.js.gz": 2435, + "a.wasm": 7985, + "a.wasm.gz": 4411, "total": 13619, - "total_gz": 7177 + "total_gz": 7223 } diff --git a/tests/code_size/random_printf_fastcomp_wasm.json b/tests/code_size/random_printf_fastcomp_wasm.json index 9832bb5d6c2a9..102829f06cf7c 100644 --- a/tests/code_size/random_printf_fastcomp_wasm.json +++ b/tests/code_size/random_printf_fastcomp_wasm.json @@ -1,6 +1,6 @@ { - "a.html": 13468, - "a.html.gz": 7113, + "a.html": 13460, + "a.html.gz": 7110, "total": 13468, - "total_gz": 7113 + "total_gz": 7110 } From 5e7e7e97aaa91afd73003653b634b404d07dc766 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 15 Apr 2020 22:33:59 -0400 Subject: [PATCH 19/34] Updates test_webidl fixture to handle promise path --- tests/webidl/post.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/webidl/post.js b/tests/webidl/post.js index 3e431f9ee129c..7e11553c307f4 100644 --- a/tests/webidl/post.js +++ b/tests/webidl/post.js @@ -1,3 +1,7 @@ +(async function main(){ +// The test setup is the same whether or not MODULARIZE is used, in which +// `TheModule` is a promise. This handles both cases. +TheModule = await Promise.resolve(TheModule); // Part 1 @@ -283,4 +287,4 @@ if (isMemoryGrowthAllowed) { // console.log('\ndone.') - +})(); \ No newline at end of file From f867846352a0bf28e2f2ff3b51f4b05e94c73bbc Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 16:47:47 -0400 Subject: [PATCH 20/34] Changes variable names to camelCase --- emcc.py | 7 +++++-- src/closure-externs/closure-externs.js | 4 ++-- src/postamble.js | 10 +++++----- src/shell_minimal.js | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/emcc.py b/emcc.py index d9dbb7586ed01..3178a6a90e8bc 100755 --- a/emcc.py +++ b/emcc.py @@ -3411,8 +3411,11 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { - var returned_promise_resolve, returned_promise_reject; - var promise = new Promise(function(resolve, reject) { returned_promise_resolve=resolve, returned_promise_reject=reject; }); + var returnedPromiseResolve, returnedPromiseReject; + var promise = new Promise(function(resolve, reject) { + returnedPromiseResolve=resolve; + returnedPromiseReject=reject; + }); %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index c9b16321cf2bc..817a0f50d17df 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1074,6 +1074,6 @@ var sampleRate; // to explicitly tell Closure Compiler about their existence since the // postamble is optimized independently /** @type {Function} */ -var returned_promise_resolve; +var returnedPromiseResolve; /** @type {Function} */ -var returned_promise_reject; \ No newline at end of file +var returnedPromiseReject; \ No newline at end of file diff --git a/src/postamble.js b/src/postamble.js index d580dd28aba7e..5d646979d117c 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -70,7 +70,7 @@ if (memoryInitializer) { readAsync(memoryInitializer, applyMemoryInitializer, function() { var e = new Error('could not load memory initializer ' + memoryInitializer); #if MODULARIZE - returned_promise_reject(e); + returnedPromiseReject(e); #else throw e; #endif @@ -295,7 +295,7 @@ function run(args) { preMain(); #if MODULARIZE - returned_promise_resolve(Module); + returnedPromiseResolve(Module); #endif #if expectToReceiveOnModule('onRuntimeInitialized') if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); @@ -410,13 +410,13 @@ function exit(status, implicit) { var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'; err(msg); #if MODULARIZE - returned_promise_reject(msg); + returnedPromiseReject(msg); #endif // MODULARIZE #else var msg = 'program exited (with status: ' + status + '), but noExitRuntime is set 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)'; err(msg); #if MODULARIZE - returned_promise_reject(msg); + returnedPromiseReject(msg); #endif // MODULARIZE #endif // EXIT_RUNTIME } @@ -482,7 +482,7 @@ if (!ENVIRONMENT_IS_PTHREAD) { // of the Module `run`. The workers/pthreads don't execute `run` here, they // call `run` in response to a message at a later time, so the creation // promise can be resolved, marking the pthread-Module as initialized. - returned_promise_resolve(Module); + returnedPromiseResolve(Module); #endif // MODULARIZE } #else diff --git a/src/shell_minimal.js b/src/shell_minimal.js index b48f9c46e84ef..a7caf3f2ca132 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -132,7 +132,7 @@ function err(text) { // the program. function ready() { #if MODULARIZE - returned_promise_resolve(Module); + returnedPromiseResolve(Module); #endif // MODULARIZE #if INVOKE_RUN && hasExportedFunction('_main') #if USE_PTHREADS From 3be551efa5314b8a14824606d32b82623d7e084d Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 16:56:59 -0400 Subject: [PATCH 21/34] Removes externs for promise variables --- src/closure-externs/closure-externs.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 817a0f50d17df..9933aa01ef67f 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1068,12 +1068,4 @@ AudioWorkletNode.prototype.onprocessorerror; var registerProcessor = function(name, obj) {}; var currentFrame; var currentTime; -var sampleRate; - -// These functions are declared in emcc.py but used in postamble.js; we need -// to explicitly tell Closure Compiler about their existence since the -// postamble is optimized independently -/** @type {Function} */ -var returnedPromiseResolve; -/** @type {Function} */ -var returnedPromiseReject; \ No newline at end of file +var sampleRate; \ No newline at end of file From 8f8e1df5695d330b8b250fc0a7ecfc30b273b8d4 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 17:37:05 -0400 Subject: [PATCH 22/34] Removes a trailing whitespace --- emcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index 3178a6a90e8bc..f4e18accbf90c 100755 --- a/emcc.py +++ b/emcc.py @@ -3412,7 +3412,7 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { var returnedPromiseResolve, returnedPromiseReject; - var promise = new Promise(function(resolve, reject) { + var promise = new Promise(function(resolve, reject) { returnedPromiseResolve=resolve; returnedPromiseReject=reject; }); From 5b02d47cd6db52e3d53e2e056c2ded25c9a9377a Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 18:00:27 -0400 Subject: [PATCH 23/34] Reworks webidl test fixture --- tests/webidl/post.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/webidl/post.js b/tests/webidl/post.js index 7e11553c307f4..4e0b538af8e01 100644 --- a/tests/webidl/post.js +++ b/tests/webidl/post.js @@ -1,7 +1,9 @@ (async function main(){ // The test setup is the same whether or not MODULARIZE is used, in which // `TheModule` is a promise. This handles both cases. -TheModule = await Promise.resolve(TheModule); +if (TheModule instanceof Promise) { + TheModule = await TheModule; +} // Part 1 From a481aa1eda3e49e9455b949014ae23e6e7603ca8 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 18:00:41 -0400 Subject: [PATCH 24/34] Readds externs and corrects the comment --- src/closure-externs/closure-externs.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 9933aa01ef67f..563e39f07ec6d 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1068,4 +1068,13 @@ AudioWorkletNode.prototype.onprocessorerror; var registerProcessor = function(name, obj) {}; var currentFrame; var currentTime; -var sampleRate; \ No newline at end of file +var sampleRate; + +// These functions are declared in emcc.py, but the Closure Compiler +// optimization occurs before that declaration is a part of the +// generated code, so we must explicitly tell Closure Compiler about +// their existence. +/** @type {Function} */ +var returnedPromiseResolve; +/** @type {Function} */ +var returnedPromiseReject; \ No newline at end of file From 955401a50447163de55fab48000dd4a9e0729435 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 18:33:09 -0400 Subject: [PATCH 25/34] Moves the closure compiler declarations & updates code sizes --- src/closure-externs/closure-externs.js | 11 +---------- src/shell.js | 8 ++++++++ src/shell_minimal.js | 8 ++++++++ tests/code_size/hello_webgl2_fastcomp_asmjs.json | 6 +++--- tests/code_size/hello_webgl2_fastcomp_wasm.json | 6 +++--- tests/code_size/hello_webgl2_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm2js.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_asmjs.json | 6 +++--- tests/code_size/hello_webgl_fastcomp_wasm.json | 6 +++--- tests/code_size/hello_webgl_wasm.json | 8 ++++---- tests/code_size/hello_webgl_wasm2js.json | 8 ++++---- 11 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 563e39f07ec6d..9933aa01ef67f 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1068,13 +1068,4 @@ AudioWorkletNode.prototype.onprocessorerror; var registerProcessor = function(name, obj) {}; var currentFrame; var currentTime; -var sampleRate; - -// These functions are declared in emcc.py, but the Closure Compiler -// optimization occurs before that declaration is a part of the -// generated code, so we must explicitly tell Closure Compiler about -// their existence. -/** @type {Function} */ -var returnedPromiseResolve; -/** @type {Function} */ -var returnedPromiseReject; \ No newline at end of file +var sampleRate; \ No newline at end of file diff --git a/src/shell.js b/src/shell.js index cc5c51b115663..b1df5ee06c9b0 100644 --- a/src/shell.js +++ b/src/shell.js @@ -32,6 +32,14 @@ var /** @type {{ preloadResults: Object }} */ Module; +#if MODULARIZE +// These variables types are declared here instead of where they're really +// created in emcc.py so that the Closure Compiler will know they exist. +/** @type {Function} */ +var returnedPromiseResolve; +/** @type {Function} */ +var returnedPromiseReject; +#endif // MODULARIZE if (!Module) /** @suppress{checkTypes}*/Module = {"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1}; #else var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : {}; diff --git a/src/shell_minimal.js b/src/shell_minimal.js index a7caf3f2ca132..aaa20997974a4 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -9,6 +9,14 @@ d #if USE_CLOSURE_COMPILER // if (!Module)` is crucial for Closure Compiler here as it will otherwise replace every `Module` occurrence with the object below var /** @type{Object} */ Module; +#if MODULARIZE +// These variables types are declared here instead of where they're really +// created in emcc.py so that the Closure Compiler will know they exist. +/** @type {Function} */ +var returnedPromiseResolve; +/** @type {Function} */ +var returnedPromiseReject; +#endif // MODULARIZE if (!Module) /** @suppress{checkTypes}*/Module = {"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1}; #else var Module = {{{ EXPORT_NAME }}}; diff --git a/tests/code_size/hello_webgl2_fastcomp_asmjs.json b/tests/code_size/hello_webgl2_fastcomp_asmjs.json index a1d3cc1a4c74c..2eadb94a60719 100644 --- a/tests/code_size/hello_webgl2_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl2_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5565, - "a.js.gz": 2577, + "a.js": 5541, + "a.js.gz": 2580, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9806, "a.asm.js.gz": 3516, "total": 16272, - "total_gz": 6694 + "total_gz": 6697 } diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index 48ffadcccdb7b..e76052cdc7494 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5531, - "a.js.gz": 2606, + "a.js": 5507, + "a.js.gz": 2609, "a.wasm": 7985, "a.wasm.gz": 4411, "total": 14079, - "total_gz": 7394 + "total_gz": 7397 } diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index 9b2f89f8b78f2..ca7ee21973c07 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5312, - "a.js.gz": 2493, + "a.js": 5288, + "a.js.gz": 2494, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16769, - "total_gz": 9790 + "total": 16745, + "total_gz": 9791 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index e372dc5bbef1e..802ec2c0e7204 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23914, - "a.js.gz": 8966, + "a.js": 23890, + "a.js.gz": 8971, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27670, - "total_gz": 12063 + "total": 27646, + "total_gz": 12068 } diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index 0166c00878452..7681fa24a5dee 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5111, - "a.js.gz": 2424, + "a.js": 5087, + "a.js.gz": 2426, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9806, "a.asm.js.gz": 3516, "total": 15818, - "total_gz": 6541 + "total_gz": 6543 } diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index 62ced98e4abc1..09be2a3009111 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5023, - "a.js.gz": 2432, + "a.js": 4999, + "a.js.gz": 2429, "a.wasm": 7985, "a.wasm.gz": 4411, "total": 13571, - "total_gz": 7220 + "total_gz": 7217 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index f13444999e765..866415551cbb7 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4801, - "a.js.gz": 2314, + "a.js": 4777, + "a.js.gz": 2316, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16258, - "total_gz": 9611 + "total": 16234, + "total_gz": 9613 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index 1def5dad33b56..cff2bcbce404f 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23408, - "a.js.gz": 8803, + "a.js": 23384, + "a.js.gz": 8808, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27164, - "total_gz": 11900 + "total": 27140, + "total_gz": 11905 } From e731dd6ca4a13d107b5a08788c66f3955dc3cb18 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 18:39:36 -0400 Subject: [PATCH 26/34] Updates comment in post.js --- tests/webidl/post.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/webidl/post.js b/tests/webidl/post.js index 4e0b538af8e01..7db330837ec15 100644 --- a/tests/webidl/post.js +++ b/tests/webidl/post.js @@ -1,6 +1,5 @@ (async function main(){ -// The test setup is the same whether or not MODULARIZE is used, in which -// `TheModule` is a promise. This handles both cases. +// If MODULARIZE is used, `TheModule` is a promise. if (TheModule instanceof Promise) { TheModule = await TheModule; } From 333eb3ba45eb5ab3d7d40540289c513676b0c0d5 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Wed, 22 Apr 2020 19:43:40 -0400 Subject: [PATCH 27/34] Moves closure compiler declarations back to externs Putting them in the shell files didn't work because they were still renamed as part of optimization, resulting in a naming mismatch. --- src/closure-externs/closure-externs.js | 10 +++++++++- src/shell.js | 8 -------- src/shell_minimal.js | 8 -------- tests/code_size/hello_webgl2_fastcomp_asmjs.json | 8 ++++---- tests/code_size/hello_webgl2_fastcomp_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm2js.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_asmjs.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_wasm.json | 4 ++-- tests/code_size/hello_webgl_wasm.json | 4 ++-- tests/code_size/hello_webgl_wasm2js.json | 8 ++++---- 11 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 9933aa01ef67f..40ed70945da06 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1068,4 +1068,12 @@ AudioWorkletNode.prototype.onprocessorerror; var registerProcessor = function(name, obj) {}; var currentFrame; var currentTime; -var sampleRate; \ No newline at end of file +var sampleRate; + +// These are here because they're declared as part of code generation in +// `modularize` in emcc.py, which isn't executed until after optimization with +// Closure Compiler has been performed. +/** @type {Function} */ +var returnedPromiseResolve; +/** @type {Function} */ +var returnedPromiseReject; \ No newline at end of file diff --git a/src/shell.js b/src/shell.js index b1df5ee06c9b0..cc5c51b115663 100644 --- a/src/shell.js +++ b/src/shell.js @@ -32,14 +32,6 @@ var /** @type {{ preloadResults: Object }} */ Module; -#if MODULARIZE -// These variables types are declared here instead of where they're really -// created in emcc.py so that the Closure Compiler will know they exist. -/** @type {Function} */ -var returnedPromiseResolve; -/** @type {Function} */ -var returnedPromiseReject; -#endif // MODULARIZE if (!Module) /** @suppress{checkTypes}*/Module = {"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1}; #else var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : {}; diff --git a/src/shell_minimal.js b/src/shell_minimal.js index aaa20997974a4..a7caf3f2ca132 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -9,14 +9,6 @@ d #if USE_CLOSURE_COMPILER // if (!Module)` is crucial for Closure Compiler here as it will otherwise replace every `Module` occurrence with the object below var /** @type{Object} */ Module; -#if MODULARIZE -// These variables types are declared here instead of where they're really -// created in emcc.py so that the Closure Compiler will know they exist. -/** @type {Function} */ -var returnedPromiseResolve; -/** @type {Function} */ -var returnedPromiseReject; -#endif // MODULARIZE if (!Module) /** @suppress{checkTypes}*/Module = {"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1}; #else var Module = {{{ EXPORT_NAME }}}; diff --git a/tests/code_size/hello_webgl2_fastcomp_asmjs.json b/tests/code_size/hello_webgl2_fastcomp_asmjs.json index 2eadb94a60719..092e6dbb4b84b 100644 --- a/tests/code_size/hello_webgl2_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl2_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5541, - "a.js.gz": 2580, + "a.js": 5555, + "a.js.gz": 2577, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9806, "a.asm.js.gz": 3516, - "total": 16272, - "total_gz": 6697 + "total": 16248, + "total_gz": 6694 } diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index e76052cdc7494..a8e55798976e9 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5507, - "a.js.gz": 2609, + "a.js": 5521, + "a.js.gz": 2607, "a.wasm": 7985, "a.wasm.gz": 4411, - "total": 14079, - "total_gz": 7397 + "total": 14055, + "total_gz": 7395 } diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index ca7ee21973c07..6387c481f298b 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5288, - "a.js.gz": 2494, + "a.js": 5302, + "a.js.gz": 2493, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16745, - "total_gz": 9791 + "total": 16759, + "total_gz": 9790 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index 802ec2c0e7204..39b0ef0876d33 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23890, - "a.js.gz": 8971, + "a.js": 23904, + "a.js.gz": 8969, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27646, - "total_gz": 12068 + "total": 27660, + "total_gz": 12066 } diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index 7681fa24a5dee..1fde725e7902e 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5087, - "a.js.gz": 2426, + "a.js": 5101, + "a.js.gz": 2424, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9806, "a.asm.js.gz": 3516, - "total": 15818, - "total_gz": 6543 + "total": 15794, + "total_gz": 6541 } diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index 09be2a3009111..ff0dedac43585 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4999, + "a.js": 5013, "a.js.gz": 2429, "a.wasm": 7985, "a.wasm.gz": 4411, - "total": 13571, + "total": 13547, "total_gz": 7217 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index 866415551cbb7..1e755aab41899 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4777, + "a.js": 4791, "a.js.gz": 2316, "a.wasm": 10894, "a.wasm.gz": 6920, - "total": 16234, + "total": 16248, "total_gz": 9613 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index cff2bcbce404f..98eaad6343911 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23384, - "a.js.gz": 8808, + "a.js": 23398, + "a.js.gz": 8805, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27140, - "total_gz": 11905 + "total": 27154, + "total_gz": 11902 } From 124234f25778e5449ce459f2c945bc3f01a65a45 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Mon, 4 May 2020 18:55:21 -0400 Subject: [PATCH 28/34] Updates code sizes --- tests/code_size/hello_webgl2_fastcomp_asmjs.json | 10 +++++----- tests/code_size/hello_webgl2_fastcomp_wasm.json | 10 +++++----- tests/code_size/hello_webgl2_wasm.json | 12 ++++++------ tests/code_size/hello_webgl2_wasm2js.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_asmjs.json | 10 +++++----- tests/code_size/hello_webgl_fastcomp_wasm.json | 10 +++++----- tests/code_size/hello_webgl_wasm.json | 12 ++++++------ tests/code_size/hello_webgl_wasm2js.json | 8 ++++---- tests/code_size/random_printf_wasm.json | 6 +++--- tests/code_size/random_printf_wasm2js.json | 8 ++++---- 10 files changed, 47 insertions(+), 47 deletions(-) diff --git a/tests/code_size/hello_webgl2_fastcomp_asmjs.json b/tests/code_size/hello_webgl2_fastcomp_asmjs.json index 1da5198759449..3bfd107e7a568 100644 --- a/tests/code_size/hello_webgl2_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl2_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5555, - "a.js.gz": 2577, + "a.js": 5559, + "a.js.gz": 2583, "a.mem": 321, "a.mem.gz": 219, - "a.asm.js": 9806, - "a.asm.js.gz": 3516, + "a.asm.js": 9846, + "a.asm.js.gz": 3535, "total": 16262, - "total_gz": 6694 + "total_gz": 6719 } diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index cdb90b7a0f982..6e84299f55ca3 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5521, - "a.js.gz": 2607, - "a.wasm": 7985, - "a.wasm.gz": 4411, + "a.js": 5526, + "a.js.gz": 2613, + "a.wasm": 8007, + "a.wasm.gz": 4421, "total": 14069, - "total_gz": 7395 + "total_gz": 7411 } diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index 6387c481f298b..7ab4402dc6c7d 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5302, - "a.js.gz": 2493, - "a.wasm": 10894, - "a.wasm.gz": 6920, - "total": 16759, - "total_gz": 9790 + "a.js": 5306, + "a.js.gz": 2498, + "a.wasm": 10912, + "a.wasm.gz": 6940, + "total": 16777, + "total_gz": 9815 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index 39b0ef0876d33..03bbc8a7303c0 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23904, - "a.js.gz": 8969, + "a.js": 23938, + "a.js.gz": 8972, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27660, - "total_gz": 12066 + "total": 27694, + "total_gz": 12069 } diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index 0add664c1d52c..ea6d010e31d63 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5101, - "a.js.gz": 2424, + "a.js": 5105, + "a.js.gz": 2428, "a.mem": 321, "a.mem.gz": 219, - "a.asm.js": 9806, - "a.asm.js.gz": 3516, + "a.asm.js": 9846, + "a.asm.js.gz": 3535, "total": 15808, - "total_gz": 6541 + "total_gz": 6564 } diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index 0cf8ebf639e93..4eb67f717f213 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5009, - "a.js.gz": 2428, - "a.wasm": 7985, - "a.wasm.gz": 4411, + "a.js": 5012, + "a.js.gz": 2431, + "a.wasm": 8007, + "a.wasm.gz": 4421, "total": 13557, - "total_gz": 7216 + "total_gz": 7229 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index f3dd78e02a7ec..a9243b1bea55e 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4787, - "a.js.gz": 2314, - "a.wasm": 10894, - "a.wasm.gz": 6920, - "total": 16244, - "total_gz": 9611 + "a.js": 4791, + "a.js.gz": 2319, + "a.wasm": 10912, + "a.wasm.gz": 6940, + "total": 16262, + "total_gz": 9636 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index 9be6e890e8353..752ce8adc4ad0 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23394, - "a.js.gz": 8805, + "a.js": 23428, + "a.js.gz": 8812, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27150, - "total_gz": 11902 + "total": 27184, + "total_gz": 11909 } diff --git a/tests/code_size/random_printf_wasm.json b/tests/code_size/random_printf_wasm.json index e98f51a8971d7..ff66e5ddae37a 100644 --- a/tests/code_size/random_printf_wasm.json +++ b/tests/code_size/random_printf_wasm.json @@ -1,6 +1,6 @@ { "a.html": 13724, - "a.html.gz": 7318, - "total": 13732, - "total_gz": 7318 + "a.html.gz": 7323, + "total": 13724, + "total_gz": 7323 } diff --git a/tests/code_size/random_printf_wasm2js.json b/tests/code_size/random_printf_wasm2js.json index dfdbf639c20e2..1acdf99040fdd 100644 --- a/tests/code_size/random_printf_wasm2js.json +++ b/tests/code_size/random_printf_wasm2js.json @@ -1,6 +1,6 @@ { - "a.html": 19930, - "a.html.gz": 8343, - "total": 19933, - "total_gz": 8343 + "a.html": 19929, + "a.html.gz": 8345, + "total": 19930, + "total_gz": 8345 } From b5bab7ce7e2726ff95b46996f49b7ca5514add6c Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Mon, 4 May 2020 19:26:59 -0400 Subject: [PATCH 29/34] Removes extra #endif Also reverts some minor changes no longer needed --- emcc.py | 7 ++++--- src/worker.js | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emcc.py b/emcc.py index e8b5c63deb324..0baafdec2cdee 100755 --- a/emcc.py +++ b/emcc.py @@ -3436,10 +3436,11 @@ def modularize(): final = final + '.modular.js' with open(final, 'w') as f: f.write(src) - export_name = shared.Settings.EXPORT_NAME + # Export using a UMD style export, or ES6 exports if selected + if shared.Settings.EXPORT_ES6: - f.write('''export default %s;''' % export_name) + f.write('''export default %s;''' % shared.Settings.EXPORT_NAME) elif not shared.Settings.MINIMAL_RUNTIME: f.write('''if (typeof exports === 'object' && typeof module === 'object') module.exports = %(EXPORT_NAME)s; @@ -3448,7 +3449,7 @@ def modularize(): else if (typeof exports === 'object') exports["%(EXPORT_NAME)s"] = %(EXPORT_NAME)s; ''' % { - 'EXPORT_NAME': export_name + 'EXPORT_NAME': shared.Settings.EXPORT_NAME }) save_intermediate('modularized') diff --git a/src/worker.js b/src/worker.js index d175f430173fd..c05770f83ddd3 100644 --- a/src/worker.js +++ b/src/worker.js @@ -159,7 +159,6 @@ this.onmessage = function(e) { }); #endif #endif -#endif #if !MODULARIZE && (!MINIMAL_RUNTIME || !WASM) // MINIMAL_RUNTIME always compiled Wasm (&Wasm2JS) asynchronously, even in pthreads. But From 4226a98ebbb449dbf2f718ebc66cc2e7e61cdba8 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Thu, 7 May 2020 12:02:51 -0400 Subject: [PATCH 30/34] Moves modularize promise initialization to shell --- emcc.py | 8 +------- src/closure-externs/closure-externs.js | 10 +--------- src/postamble.js | 10 +++++----- src/shell.js | 9 +++++++++ src/shell_minimal.js | 11 ++++++++++- tests/code_size/hello_webgl2_fastcomp_asmjs.json | 8 ++++---- tests/code_size/hello_webgl2_fastcomp_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm.json | 8 ++++---- tests/code_size/hello_webgl2_wasm2js.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_asmjs.json | 8 ++++---- tests/code_size/hello_webgl_fastcomp_wasm.json | 8 ++++---- tests/code_size/hello_webgl_wasm.json | 8 ++++---- tests/code_size/hello_webgl_wasm2js.json | 8 ++++---- tests/code_size/random_printf_wasm2js.json | 2 +- 14 files changed, 59 insertions(+), 55 deletions(-) diff --git a/emcc.py b/emcc.py index 0baafdec2cdee..ac8b1e816a6e6 100755 --- a/emcc.py +++ b/emcc.py @@ -3387,17 +3387,11 @@ def modularize(): src = ''' function(%(EXPORT_NAME)s) { - var returnedPromiseResolve, returnedPromiseReject; - var promise = new Promise(function(resolve, reject) { - returnedPromiseResolve=resolve; - returnedPromiseReject=reject; - }); - %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; %(src)s - return promise; + return %(EXPORT_NAME)s.ready; } ''' % { 'EXPORT_NAME': shared.Settings.EXPORT_NAME, diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 40ed70945da06..9933aa01ef67f 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -1068,12 +1068,4 @@ AudioWorkletNode.prototype.onprocessorerror; var registerProcessor = function(name, obj) {}; var currentFrame; var currentTime; -var sampleRate; - -// These are here because they're declared as part of code generation in -// `modularize` in emcc.py, which isn't executed until after optimization with -// Closure Compiler has been performed. -/** @type {Function} */ -var returnedPromiseResolve; -/** @type {Function} */ -var returnedPromiseReject; \ No newline at end of file +var sampleRate; \ No newline at end of file diff --git a/src/postamble.js b/src/postamble.js index 5d646979d117c..c6c416ca6fbd3 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -70,7 +70,7 @@ if (memoryInitializer) { readAsync(memoryInitializer, applyMemoryInitializer, function() { var e = new Error('could not load memory initializer ' + memoryInitializer); #if MODULARIZE - returnedPromiseReject(e); + readyPromiseReject(e); #else throw e; #endif @@ -295,7 +295,7 @@ function run(args) { preMain(); #if MODULARIZE - returnedPromiseResolve(Module); + readyPromiseResolve(Module); #endif #if expectToReceiveOnModule('onRuntimeInitialized') if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); @@ -410,13 +410,13 @@ function exit(status, implicit) { var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'; err(msg); #if MODULARIZE - returnedPromiseReject(msg); + readyPromiseReject(msg); #endif // MODULARIZE #else var msg = 'program exited (with status: ' + status + '), but noExitRuntime is set 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)'; err(msg); #if MODULARIZE - returnedPromiseReject(msg); + readyPromiseReject(msg); #endif // MODULARIZE #endif // EXIT_RUNTIME } @@ -482,7 +482,7 @@ if (!ENVIRONMENT_IS_PTHREAD) { // of the Module `run`. The workers/pthreads don't execute `run` here, they // call `run` in response to a message at a later time, so the creation // promise can be resolved, marking the pthread-Module as initialized. - returnedPromiseResolve(Module); + readyPromiseResolve(Module); #endif // MODULARIZE } #else diff --git a/src/shell.js b/src/shell.js index 628f157509416..bf19ad75965c9 100644 --- a/src/shell.js +++ b/src/shell.js @@ -38,6 +38,15 @@ var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : #endif // USE_CLOSURE_COMPILER #endif // SIDE_MODULE +#if MODULARIZE +// Set up the promise that indicates the Module is initialized +var readyPromiseResolve, readyPromiseReject; +Module['ready'] = new Promise(function(resolve, reject) { + readyPromiseResolve=resolve; + readyPromiseReject=reject; +}); +#endif + // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) // {{PRE_JSES}} diff --git a/src/shell_minimal.js b/src/shell_minimal.js index d72cee42179c8..12e347c986fac 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -15,6 +15,15 @@ var Module = {{{ EXPORT_NAME }}}; #endif // USE_CLOSURE_COMPILER #endif // SIDE_MODULE +#if MODULARIZE +// Set up the promise that indicates the Module is initialized +var readyPromiseResolve, readyPromiseReject; +Module['ready'] = new Promise(function(resolve, reject) { + readyPromiseResolve=resolve; + readyPromiseReject=reject; +}); +#endif + #if ENVIRONMENT_MAY_BE_NODE var ENVIRONMENT_IS_NODE = typeof process === 'object'; #endif @@ -132,7 +141,7 @@ function err(text) { // the program. function ready() { #if MODULARIZE - returnedPromiseResolve(Module); + readyPromiseResolve(Module); #endif // MODULARIZE #if INVOKE_RUN && hasExportedFunction('_main') #if USE_PTHREADS diff --git a/tests/code_size/hello_webgl2_fastcomp_asmjs.json b/tests/code_size/hello_webgl2_fastcomp_asmjs.json index 3bfd107e7a568..243cce98e5546 100644 --- a/tests/code_size/hello_webgl2_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl2_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5559, - "a.js.gz": 2583, + "a.js": 5388, + "a.js.gz": 2546, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9846, "a.asm.js.gz": 3535, - "total": 16262, - "total_gz": 6719 + "total": 16135, + "total_gz": 6682 } diff --git a/tests/code_size/hello_webgl2_fastcomp_wasm.json b/tests/code_size/hello_webgl2_fastcomp_wasm.json index 6e84299f55ca3..fe7ed97d6df2b 100644 --- a/tests/code_size/hello_webgl2_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl2_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5526, - "a.js.gz": 2613, + "a.js": 5353, + "a.js.gz": 2570, "a.wasm": 8007, "a.wasm.gz": 4421, - "total": 14069, - "total_gz": 7411 + "total": 13923, + "total_gz": 7368 } diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index 7ab4402dc6c7d..bc78b6188aaae 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5306, - "a.js.gz": 2498, + "a.js": 5133, + "a.js.gz": 2460, "a.wasm": 10912, "a.wasm.gz": 6940, - "total": 16777, - "total_gz": 9815 + "total": 16608, + "total_gz": 9777 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index 03bbc8a7303c0..93cab80cf12ee 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23938, - "a.js.gz": 8972, + "a.js": 23765, + "a.js.gz": 8937, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27694, - "total_gz": 12069 + "total": 27521, + "total_gz": 12034 } diff --git a/tests/code_size/hello_webgl_fastcomp_asmjs.json b/tests/code_size/hello_webgl_fastcomp_asmjs.json index ea6d010e31d63..7c7c291cb854b 100644 --- a/tests/code_size/hello_webgl_fastcomp_asmjs.json +++ b/tests/code_size/hello_webgl_fastcomp_asmjs.json @@ -1,12 +1,12 @@ { "a.html": 580, "a.html.gz": 382, - "a.js": 5105, - "a.js.gz": 2428, + "a.js": 4932, + "a.js.gz": 2386, "a.mem": 321, "a.mem.gz": 219, "a.asm.js": 9846, "a.asm.js.gz": 3535, - "total": 15808, - "total_gz": 6564 + "total": 15679, + "total_gz": 6522 } diff --git a/tests/code_size/hello_webgl_fastcomp_wasm.json b/tests/code_size/hello_webgl_fastcomp_wasm.json index 4eb67f717f213..676a099834ea1 100644 --- a/tests/code_size/hello_webgl_fastcomp_wasm.json +++ b/tests/code_size/hello_webgl_fastcomp_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5012, - "a.js.gz": 2431, + "a.js": 4839, + "a.js.gz": 2389, "a.wasm": 8007, "a.wasm.gz": 4421, - "total": 13557, - "total_gz": 7229 + "total": 13409, + "total_gz": 7187 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index a9243b1bea55e..3a69216a17921 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4791, - "a.js.gz": 2319, + "a.js": 4618, + "a.js.gz": 2276, "a.wasm": 10912, "a.wasm.gz": 6940, - "total": 16262, - "total_gz": 9636 + "total": 16093, + "total_gz": 9593 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index 752ce8adc4ad0..716311075bf52 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 23428, - "a.js.gz": 8812, + "a.js": 23255, + "a.js.gz": 8767, "a.mem": 3168, "a.mem.gz": 2711, - "total": 27184, - "total_gz": 11909 + "total": 27011, + "total_gz": 11864 } diff --git a/tests/code_size/random_printf_wasm2js.json b/tests/code_size/random_printf_wasm2js.json index 1acdf99040fdd..b6e2a4a8996f1 100644 --- a/tests/code_size/random_printf_wasm2js.json +++ b/tests/code_size/random_printf_wasm2js.json @@ -1,6 +1,6 @@ { "a.html": 19929, "a.html.gz": 8345, - "total": 19930, + "total": 19929, "total_gz": 8345 } From fc0078c6c51088dede650032673e49b71eaa8b96 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Fri, 8 May 2020 15:28:25 -0400 Subject: [PATCH 31/34] Adds some whitespace --- src/shell.js | 4 ++-- src/shell_minimal.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shell.js b/src/shell.js index bf19ad75965c9..d820d97fe4d3a 100644 --- a/src/shell.js +++ b/src/shell.js @@ -42,8 +42,8 @@ var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : // Set up the promise that indicates the Module is initialized var readyPromiseResolve, readyPromiseReject; Module['ready'] = new Promise(function(resolve, reject) { - readyPromiseResolve=resolve; - readyPromiseReject=reject; + readyPromiseResolve = resolve; + readyPromiseReject = reject; }); #endif diff --git a/src/shell_minimal.js b/src/shell_minimal.js index 12e347c986fac..f872b1fe6ec07 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -19,8 +19,8 @@ var Module = {{{ EXPORT_NAME }}}; // Set up the promise that indicates the Module is initialized var readyPromiseResolve, readyPromiseReject; Module['ready'] = new Promise(function(resolve, reject) { - readyPromiseResolve=resolve; - readyPromiseReject=reject; + readyPromiseResolve = resolve; + readyPromiseReject = reject; }); #endif From 2c84ebf584acbc65243f9f104ea6b163f92d1625 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Fri, 8 May 2020 16:03:28 -0400 Subject: [PATCH 32/34] Updates the docs with new MODULARIZE behavior --- site/source/docs/getting_started/FAQ.rst | 17 ++--------- .../WebIDL-Binder.rst | 29 ++++++++----------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst index e4ee630786d00..83b8c95a6182e 100644 --- a/site/source/docs/getting_started/FAQ.rst +++ b/site/source/docs/getting_started/FAQ.rst @@ -262,24 +262,13 @@ Here is an example of how to use it: The crucial thing is that ``Module`` exists, and has the property ``onRuntimeInitialized``, before the script containing emscripten output (``my_project.js`` in this example) is loaded. -Another option is to use the ``MODULARIZE`` option, using ``-s MODULARIZE=1``. That will put all of the generated JavaScript in a function, which you can call to create an instance. The instance has a promise-like `.then()` method, so if you build with say ``-s MODULARIZE=1 -s 'EXPORT_NAME="MyCode"'`` (see details in settings.js), then you can do something like this: +Another option is to use the ``MODULARIZE`` option, using ``-s MODULARIZE=1``. That puts all of the generated JavaScript into a factory function, which you can call to create an instance of your module. The factory function returns a Promise that resolves with the module instance. The promise is resolved once it's safe to call the compiled code, i.e. after the compiled code has been downloaded and instantiated. For example, if you build with ``-s MODULARIZE=1 -s 'EXPORT_NAME="createMyModule"'`` (see details in settings.js), then you can do this: :: - MyCode().then(function(Module) { - // this is reached when everything is ready, and you can call methods on Module + createMyModule().then((myModule) => { + // this is reached when everything is ready, and you can call methods on myModule }); - -.. note:: Be careful with using ``Module.then()`` inside ``Promise.resolve()`` or ``await`` statements. ``Module.then()`` resolves with ``Module`` which still has ``then``, so the ``await`` statement loops indefinitely. If you need to use ``Module.then()`` with ``await`` statement, you can use this workaround: - - :: - - await Module.then(m => { - delete m['then']; - resolve(m); - }); - - For more information read `this issue `_. .. _faq-NO_EXIT_RUNTIME: diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst b/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst index 156223cb00ddd..2ecbc18df5e97 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst @@ -113,28 +113,23 @@ Modular output When using the WebIDL binder, often what you are doing is creating a library. In that case, the `MODULARIZE` option makes sense to use. It wraps the entire JavaScript output -in a function, which you call to create instances, +in a function, and returns a Promise which resolves to the initialized Module instance. .. code-block:: javascript - var instance = Module(); - -(You can use the `EXPORT_NAME` option to change `Module` to something else.) This is -good practice for libraries, as then they don't include unnecessary things in the -global scope (and in some cases you want to create more than one). - -Modularize also provides a promise-like API, which is the recommended way to use it, - -.. code-block:: javascript - - var instance = Module().then(function(instance) { - // code that uses the instance here + var instance; + Module().then(module => { + instance = module; }); -The callback is called when it is safe to run compiled code, similar -to the `onRuntimeInitialized` callback (i.e., it waits for all -necessary async events). It receives the instance as a parameter, -for convenience. +The promise is resolved when it is safe to run compiled code, i.e. after it +has been has been downloaded and instantiated. The promise is resolved at the +same time the `onRuntimeInitialized` callback is invoked, so there's no need to +use `onRuntimeInitialized` when using `MODULARIZE`. + +You can use the `EXPORT_NAME` option to change `Module` to something else. This is +good practice for libraries, as then they don't include unnecessary things in the +global scope, and in some cases you want to create more than one. Using C++ classes in JavaScript From 48ab6dddd9ee08ff59f509af91ffce779ad3e0f2 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Fri, 8 May 2020 16:13:52 -0400 Subject: [PATCH 33/34] Updates changelog with MODULARIZE change --- ChangeLog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 1ad000da341ff..b51515f48d4cc 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,10 @@ Current Trunk 1.39.15: 05/06/2020 ------------------- +- Change the factory function created by using the `MODULARIZE` build option to + return a Promise instead of a module instance, and remove the `then` method + from the instance (#10697). This fixes the bug where using `await` on the instance in + an async function would cause an infinite loop (#5820). - Add `--extern-pre-js` and `--extern-post-js` emcc flags. Files provided there are prepended/appended to the final JavaScript output, *after* all other work has been done, including optimization, optional `MODULARIZE`-ation, From 86208bb6da85b8e36462aa3b57721e0b6419a589 Mon Sep 17 00:00:00 2001 From: Louis DeScioli Date: Fri, 8 May 2020 17:41:58 -0400 Subject: [PATCH 34/34] Updates settings.js for new MODULARIZE behavior --- ChangeLog.md | 6 ++--- src/settings.js | 69 +++++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index b51515f48d4cc..cc5195683ab1d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -21,9 +21,9 @@ Current Trunk 1.39.15: 05/06/2020 ------------------- - Change the factory function created by using the `MODULARIZE` build option to - return a Promise instead of a module instance, and remove the `then` method - from the instance (#10697). This fixes the bug where using `await` on the instance in - an async function would cause an infinite loop (#5820). + return a Promise instead of the module instance. If you use `MODULARIZE` you + will need to wait on the returned Promise, using `await` or its `then` + callback, to get the module instance (#10697). - Add `--extern-pre-js` and `--extern-post-js` emcc flags. Files provided there are prepended/appended to the final JavaScript output, *after* all other work has been done, including optimization, optional `MODULARIZE`-ation, diff --git a/src/settings.js b/src/settings.js index 6341aefe6d00f..a8ab4d1060a31 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1029,29 +1029,40 @@ var DETERMINISTIC = 0; // By default we emit all code in a straightforward way into the output // .js file. That means that if you load that in a script tag in a web -// page, it will use the global scope. With MODULARIZE set, we will instead emit +// page, it will use the global scope. With `MODULARIZE` set, we instead emit +// the code wrapped in a function that returns a promise. The promise is +// resolved with the module instance when it is safe to run the compiled code, +// similar to the `onRuntimeInitialized` callback. You do not need to use the +// `onRuntimeInitialized` callback when using `MODULARIZE`. +// +// The default name of the function is `Module`, but can be changed using the +// `EXPORT_NAME` option. We recommend renaming it to a more typical name for a +// factory function, e.g. `createModule`. // -// var EXPORT_NAME = function(Module) { -// Module = Module || {}; -// // .. all the emitted code from emscripten .. -// return Module; -// }; // -// where EXPORT_NAME is from the option of the same name (so, by default -// it will be var Module = ..., and so you should change EXPORT_NAME if -// you want more than one module in the same web page). +// You use the factory function like so: // -// You can then use this by something like +// const module = await EXPORT_NAME(); +// +// or: // -// var instance = EXPORT_NAME(); +// let module; +// EXPORT_NAME().then(instance => { +// module = instance; +// }); +// // -// or +// The factory function accepts 1 parameter, an object with default values for +// the module instance: // -// var instance = EXPORT_NAME({ option: value, ... }); +// const module = await EXPORT_NAME({ option: value, ... }); // // Note the parentheses - we are calling EXPORT_NAME in order to instantiate -// the module. (This allows, in particular, for you to create multiple -// instantiations, etc.) +// the module. This allows you to create multiple instances of the module. +// +// Note that in MODULARIZE mode we do *not* look for a global `Module` object +// for default values. Default values must be passed as a parameter to the +// factory function. // // The default .html shell file provided in MINIMAL_RUNTIME mode shows // an example to how the module is instantiated from within the html file. @@ -1062,28 +1073,14 @@ var DETERMINISTIC = 0; // https://github.com/emscripten-core/emscripten/issues/7950) // // If you add --pre-js or --post-js files, they will be included inside -// the module with the rest of the emitted code. That way, they can be -// optimized together with it. (If you want something outside of the module, -// that is, literally before or after all the code including the extra -// MODULARIZE code, you can do that by modifying the JS yourself after -// emscripten runs. While --pre-js and --post-js happen to do that in -// non-modularize mode, their big feature is that they add code to be -// optimized with the rest of the emitted code, allowing better dead code -// elimination and minification.) -// -// Modularize also provides a promise-like API, -// -// var instance = EXPORT_NAME().then(function(Module) { .. }); -// -// The callback is called when it is safe to run compiled code, similar -// to the onRuntimeInitialized callback (i.e., it waits for all -// necessary async events). It receives the instance as a parameter, -// for convenience. +// the factory function with the rest of the emitted code in order to be +// optimized together with it. // -// Note that in MODULARIZE mode we do *not* look at the global `Module` -// object, so if you define things there they will be ignored. The reason -// is that you will be constructing the instances manually, and can -// provide Module there, or something else, as you want. +// If you want to include code outside all of the generated code, including the +// factory function, you can use --extern-pre-js or --extern-post-js. While +// --pre-js and --post-js happen to do that in non-MODULARIZE mode, their +// intended usage is to add code that is optimized with the rest of the emitted +// code, allowing better dead code elimination and minification. var MODULARIZE = 0; // If we separate out asm.js with the --separate-asm option,