You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This makes us not exit the runtime by default. That means we don't emit code for atexits and other things that happen when the runtime shuts down, like flushing the stdio streams. This is beneficial for 2 reasons:
* For #5794, this helps remove code. It avoids all the support for shutting down the runtime, emitting atexits, etc. It also enables more optimizations (the ctor evaller in wasm can do better without calls to atexit). This removes 3% of hello world's wasm size and 0.5% of its JS.
* A saner default for the web. A program on the web that does anything asynchronous will not want the runtime to exit when main() exits, so we set this flag to 1 for many tests, which this PR lets us remove.
However, this is a breaking change. As already mentioned, the possible breakages are
* printf("hello") will not console.log since there is no newline. Only when the streams are flushed would that be printed out. So this change would make us not emit that.
* atexits do not run.
Both of those risks are mitigated in this PR: In ASSERTIONS mode, check if there is unflushed stream output, and explain what to do if so. Same if atexit is called.
This PR has a lot of test changes, some that simplify web tests - because the new default is better for the web - but others that add a param to a shell test - because the new default is less optimal in a shell environment. I think the risk here is lower than those shell tests indicate: we do test quite a lot of things in the shell, but just because it's convenient, not because that's what most users care about.
Also:
* this PR found an unnoticed bug: FORCE_FILESYSTEM didn't actually do what the name suggests. I think we just never tested it properly with NO_EXIT_RUNTIME. Fixed in this PR.
* emrun sets NO_EXIT_RUNTIME=0. it is a mode where we specifically want to get the exit code from the running program, as if it were a shell command, not a browser app
* add faq entry, and mention the faq
* fix an existing emterpreter-async bug: if we are unwinding the stack as we leave main(), then do not call exit, we are not exiting yet - code is yet to run later
* metadce is now more effective, update test
* faq entry on Module.* is not a function
* fix browser.test_emscripten_main_loop - the pthreads part needs the runtime to exit
Copy file name to clipboardExpand all lines: ChangeLog.markdown
+1
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,7 @@ Not all changes are documented here. In particular, new features, user-oriented
9
9
10
10
Current Trunk
11
11
-------------
12
+
- Breaking change: Change `NO_EXIT_RUNTIME` to 1 by default. This means that by default we don't include code to shut down the runtime, flush stdio streams, run atexits, etc., which is better for code size. When `ASSERTIONS` is on, we warn at runtime if there is text buffered in the streams that should be flushed, or atexits are used.
12
13
- Meta-DCE for JS+wasm: remove unused code between JS+wasm more aggressively. This should not break valid code, but may break code that depended on unused code being kept around (like using a function from outside the emitted JS without exporting it - only exported things are guaranteed to be kept alive through optimization).
logging.warning('you should enable -s NO_EXIT_RUNTIME=1 so that EVAL_CTORS can work at full efficiency (it gets rid of atexit calls which might disrupt EVAL_CTORS)')
1216
1219
1217
1220
# memory growth does not work in dynamic linking, except for wasm
Copy file name to clipboardExpand all lines: site/source/docs/api_reference/emscripten.h.rst
+2
Original file line number
Diff line number
Diff line change
@@ -334,6 +334,8 @@ Functions
334
334
335
335
The difference is that ``emscripten_force_exit`` will shut down the runtime even if you previously called :c:func:`emscripten_exit_with_live_runtime` or otherwise kept the runtime alive. In other words, this method gives you the option to completely shut down the runtime after it was kept alive beyond the completion of ``main()``.
336
336
337
+
Note that if ``NO_EXIT_RUNTIME`` is set (which it is by default) then the runtime cannot be shut down, as we do not include the code to do so. Build with ``-s NO_EXIT_RUNTIME=0`` if you want to be able to exit the runtime.
338
+
337
339
:param int status: The same as for the *libc* function `exit() <http://linux.die.net/man/3/exit>`_.
That method will be called when the runtime is ready and it is ok for you to call compiled code. In practice, that is exactly the same time at which ``main()`` would be called, so ``onRuntimeInitialized`` doesn't let you do anything new, but it can be convenient in some cases - for example, if you use ``onRuntimeInitialized`` and don't define a ``main()`` function, then the runtime will not be shut down after ``main()`` exits, and you can keep calling compiled methods (you can also have a ``main()`` and build with ``-s NO_EXIT_RUNTIME=1`` to keep the runtime from being shut down). Thus, for libraries, ``onRuntimeInitialized`` can be convenient.
233
+
That method will be called when the runtime is ready and it is ok for you to call compiled code. In practice, that is exactly the same time at which ``main()`` would be called, so ``onRuntimeInitialized`` doesn't let you do anything new, but you can set it from JavaScript at runtime in a flexible way.
234
234
235
235
Here is an example of how to use it:
236
236
@@ -248,6 +248,27 @@ Here is an example of how to use it:
248
248
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.
249
249
250
250
251
+
.. _faq-NO_EXIT_RUNTIME:
252
+
253
+
What does "exiting the runtime" mean? Why don't ``atexit()s`` run?
(You may need this answer if you see an error saying something like ``atexit() called, but NO_EXIT_RUNTIME`` or ``stdio streams had content in them that was not flushed. you should set NO_EXIT_RUNTIME to 0``.)
257
+
258
+
By default Emscripten sets ``NO_EXIT_RUNTIME=1``, which means that we don't include code to shut down the runtime. That means that when ``main()`` exits, we don't flush the stdio streams, or call the destructors of global C++ objects, or call ``atexit`` callbacks. This lets us emit smaller code by default, and is normally what you want on the web: even though ``main()`` exited, you may have something asynchronous happening later that you want to execute.
259
+
260
+
In some cases, though, you may want a more "commandline" experience, where we do shut down the runtime when ``main()`` exits. You can build with ``-s NO_EXIT_RUNTIME=0``, and then we will call ``atexits`` and so forth. When you build with ``ASSERTIONS``, you should get a warning when you need this. For example, if your program prints something without a newline,
261
+
262
+
::
263
+
264
+
#include <stdio.h>
265
+
266
+
int main() {
267
+
printf("hello"); // note no newline
268
+
}
269
+
270
+
If we don't shut down the runtime and flush the stdio streams, "hello" won't be printed. In an ``ASSERTIONS`` build you'll get a notification saying ``stdio streams had content in them that was not flushed. you should set NO_EXIT_RUNTIME to 0``.
271
+
251
272
.. _faq-dead-code-elimination:
252
273
253
274
Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get ``No functions to process``?
@@ -324,6 +345,14 @@ Emscripten by default does *not* give fatal errors on undefined symbols, so you
324
345
325
346
Aside from just forgetting to link in a necessary object file, one possible cause for this error is inline functions in headers. If you have a header with ``inline int my_func() { .. }`` then *Clang* may not actually inline the function (since inline is just a hint), and also not generate code for it (since it's in a header). The result is that the generated bitcode and JavaScript will not have that function implemented. One solution is to add ``static`` to the function declaration, which forces code to be generated in the object file: ``static inline int my_func() { .. }``.
326
347
348
+
Why do I get ``TypeError: Module.someThing is not a function``?
The ``Module`` object will contain exported methods. For something to appear there, you should add it to ``EXPORTED_FUNCTIONS`` for compiled code, or ``EXTRA_EXPORTED_RUNTIME_METHODS`` for a runtime method (like ``getValue``).
352
+
353
+
.. note:: You can use runtime methods directly, without exporting them, if the compiler can see them used. For example, you can use ``getValue`` in ``EM_ASM`` code, or a ``--pre-js``, by calling it directly. The optimizer will not remove that JS runtime method because it sees it is used. You only need to use ``Module.getValue`` if you want to call that method from outside the JS code the compiler can see, and then you need to export it.
354
+
355
+
.. note:: Emscripten used to export many runtime methods by default. This increased code size, and for that reason we've changed that default. If you depend on something that used to be exported, you should see a warning pointing you to the solution, in an unoptimized build, or a build with ``ASSERTIONS`` enabled, which we hope will minimize any annoyance. See ``Changelog.markdown`` for details.
327
356
328
357
Why do I get an odd python error complaining about libcxx.bc or libcxxabi.bc?
Copy file name to clipboardExpand all lines: site/source/docs/optimizing/Optimizing-Code.rst
-12
Original file line number
Diff line number
Diff line change
@@ -38,18 +38,6 @@ Advanced compiler settings
38
38
39
39
There are several flags you can :ref:`pass to the compiler <emcc-s-option-value>` to affect code generation, which will also affect performance — for example :ref:`DISABLE_EXCEPTION_CATCHING <optimizing-code-exception-catching>`. These are documented in `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_. Some of these will be directly affected by the optimization settings (you can find out which ones by searching for ``apply_opt_level`` in `tools/shared.py <https://github.com/kripken/emscripten/blob/1.29.12/tools/shared.py#L958>`_).
40
40
41
-
A few useful flags are:
42
-
43
-
-
44
-
.. _optimizing-code-no-exit-runtime:
45
-
46
-
``NO_EXIT_RUNTIME``: Building with ``-s NO_EXIT_RUNTIME=1`` lets the compiler know that you don't want to shut down the runtime environment after the ``main()`` function finishes. This allows it to discard the ``atexit`` and global destructor calls it would otherwise make, improving code size and startup speed.
47
-
48
-
This is useful if your ``main()`` function finishes but you still want to execute code, for example in an app that uses a :ref:`main loop function <emscripten-runtime-environment-main-loop>`.
49
-
50
-
.. note:: Emscripten will not shut down the runtime if it detects :c:func:`emscripten_set_main_loop`, but it is better to optimise away the unnecessary code.
Copy file name to clipboardExpand all lines: site/source/docs/tools_reference/emcc.rst
+1-1
Original file line number
Diff line number
Diff line change
@@ -405,7 +405,7 @@ Options that are modified or new in *emcc* are listed below:
405
405
.. _emcc-emrun:
406
406
407
407
``--emrun``
408
-
Enables the generated output to be aware of the :ref:`emrun <Running-html-files-with-emrun>` command line tool. This allows ``stdout``, ``stderr`` and ``exit(returncode)`` capture when running the generated application through *emrun*.
408
+
Enables the generated output to be aware of the :ref:`emrun <Running-html-files-with-emrun>` command line tool. This allows ``stdout``, ``stderr`` and ``exit(returncode)`` capture when running the generated application through *emrun*. (This enables `NO_EXIT_RUNTIME=0`, allowing normal runtime exiting with return code passing.)
409
409
410
410
``--cpuprofiler``
411
411
Embeds a simple CPU profiler onto the generated page. Use this to perform cursory interactive performance profiling.
Copy file name to clipboardExpand all lines: src/library_syscall.js
+14-1
Original file line number
Diff line number
Diff line change
@@ -779,7 +779,20 @@ var SyscallsLibrary = {
779
779
returnSYSCALLS.doReadv(stream,iov,iovcnt);
780
780
},
781
781
#if NO_FILESYSTEM
782
-
__syscall146__postset: '/* flush anything remaining in the buffer during shutdown */ __ATEXIT__.push(function() { var fflush = Module["_fflush"]; if (fflush) fflush(0); var printChar = ___syscall146.printChar; if (!printChar) return; var buffers = ___syscall146.buffers; if (buffers[1].length) printChar(1, {{{ charCode("\n") }}}); if (buffers[2].length) printChar(2, {{{ charCode("\n") }}}); });',
782
+
$flush_NO_FILESYSTEM: function(){
783
+
// flush anything remaining in the buffers during shutdown
Copy file name to clipboardExpand all lines: src/postamble.js
+58-5
Original file line number
Diff line number
Diff line change
@@ -212,8 +212,16 @@ Module['callMain'] = function callMain(args) {
212
212
Module.realPrint('main() took '+(Date.now()-start)+' milliseconds');
213
213
#endif
214
214
215
+
#if EMTERPRETIFY_ASYNC
216
+
// if we are saving the stack, then do not call exit, we are not
217
+
// really exiting now, just unwinding the JS stack
218
+
if(EmterpreterAsync.state!==1){
219
+
#endif // EMTERPRETIFY_ASYNC
215
220
// if we're not running an evented main loop, it's time to exit
216
-
exit(ret,/* implicit = */true);
221
+
exit(ret,/* implicit = */true);
222
+
#if EMTERPRETIFY_ASYNC
223
+
}
224
+
#endif // EMTERPRETIFY_ASYNC
217
225
}
218
226
catch(e){
219
227
if(einstanceofExitStatus){
@@ -313,17 +321,62 @@ function run(args) {
313
321
Module['run']=run;
314
322
315
323
functionexit(status,implicit){
316
-
if(implicit&&Module['noExitRuntime']){
317
324
#if ASSERTIONS
318
-
Module.printErr('exit('+status+') implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)');
325
+
#if NO_EXIT_RUNTIME==1
326
+
// Compiler settings do not allow exiting the runtime, so flushing
327
+
// the streams is not possible. but in ASSERTIONS mode we check
328
+
// if there was something to flush, and if so tell the user they
329
+
// should request that the runtime be exitable.
330
+
// Normally we would not even include flush() at all, but in ASSERTIONS
331
+
// builds we do so just for this check, and here we see if there is any
332
+
// content to flush, that is, we check if there would have been
333
+
// something a non-ASSERTIONS build would have not seen.
334
+
// How we flush the streams depends on whether we are in NO_FILESYSTEM
335
+
// mode (which has its own special function for this; otherwise, all
Runtime.warnOnce('stdio streams had content in them that was not flushed. you should set NO_EXIT_RUNTIME to 0 (see the FAQ), or make sure to emit a newline when you printf etc.');
356
+
}
357
+
}
358
+
#endif // NO_EXIT_RUNTIME
359
+
#endif // ASSERTIONS
360
+
361
+
// if this is just main exit-ing implicitly, and the status is 0, then we
362
+
// don't need to do anything here and can just leave. if the status is
363
+
// non-zero, though, then we need to report it.
364
+
// (we may have warned about this earlier, if a situation justifies doing so)
Module.printErr('exit('+status+') called, but noExitRuntime, 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)');
326
-
#endif
371
+
// if exit() was called, we may warn the user if the runtime isn't actually being shut down
372
+
if(!implicit){
373
+
#if NO_EXIT_RUNTIME
374
+
Module.printErr('exit(' +status+') called, but NO_EXIT_RUNTIME is set, so halting execution but not exiting the runtime or preventing further async execution (build with NO_EXIT_RUNTIME=0, if you want a true shutdown)');
375
+
#else
376
+
Module.printErr('exit('+status+') called, 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)');
0 commit comments