-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Implements Promise-based API for modularized builds #10697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
f30e444
b4ec2f4
6f4997a
fc9e049
49ae9d2
af6689d
af82a9c
b402022
63bb3af
f205061
69ba48b
cc89009
0ab8841
30209eb
b44e3a3
9219dc2
0f0166b
98eadf4
a7cd5ee
ed0fa51
5e7e7e9
19a6bd0
f867846
3be551e
8f8e1df
c6d63fc
5b02d47
a481aa1
955401a
e731dd6
333eb3b
f5691da
40bb6fc
124234f
b5bab7c
4226a98
7e3c8a1
fc0078c
2c84ebf
48ab6dd
86208bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -3400,22 +3397,20 @@ 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; | ||
| var promise = new Promise((resolve, reject) => (returned_promise_resolve=resolve, returned_promise_reject=reject)); | ||
|
|
||
| %(EXPORT_NAME)s = %(EXPORT_NAME)s || {}; | ||
|
|
||
| %(src)s | ||
|
|
||
| return %(exports_object)s | ||
| return promise; | ||
| } | ||
| ''' % { | ||
| 'EXPORT_NAME': shared.Settings.EXPORT_NAME, | ||
| 'src': src, | ||
| 'exports_object': exports_object | ||
| } | ||
|
|
||
| if not shared.Settings.MODULARIZE_INSTANCE: | ||
|
|
@@ -3450,26 +3445,32 @@ 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.). | ||
| 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; | ||
|
|
@@ -3478,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') | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -68,7 +68,12 @@ if (memoryInitializer) { | |||
| }; | ||||
| var doBrowserLoad = function() { | ||||
| readAsync(memoryInitializer, applyMemoryInitializer, function() { | ||||
| throw 'could not load memory initializer ' + memoryInitializer; | ||||
| var e = new Error('could not load memory initializer ' + memoryInitializer); | ||||
kripken marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
| #if MODULARIZE | ||||
| returned_promise_reject(e); | ||||
| #else | ||||
| throw e; | ||||
| #endif | ||||
| }); | ||||
| }; | ||||
| #if SUPPORT_BASE64_EMBEDDING | ||||
|
|
@@ -121,36 +126,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} | ||||
|
|
@@ -319,6 +294,9 @@ function run(args) { | |||
|
|
||||
| preMain(); | ||||
|
|
||||
| #if MODULARIZE | ||||
| returned_promise_resolve(Module); | ||||
| #endif | ||||
| #if expectToReceiveOnModule('onRuntimeInitialized') | ||||
| if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); | ||||
| #endif | ||||
|
|
@@ -429,9 +407,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); | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure. As far as I can tell, emscripten/src/emrun_postjs.js Line 45 in 58b49d3
So maybe
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've never seen that emrun code before, but looks like it's doing something really weird there, which is not a problem for us. So yes,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good |
||||
| #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 | ||||
|
|
@@ -484,15 +470,24 @@ 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 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. | ||||
kripken marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
| returned_promise_resolve(Module); | ||||
| #endif // MODULARIZE | ||||
| } | ||||
| #else | ||||
| run(); | ||||
| #endif | ||||
| #endif // USE_PTHREADS | ||||
|
|
||||
| #if BUILD_AS_WORKER | ||||
|
|
||||
|
|
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.