updates to the porting guidelines documents

This commit is contained in:
hamishwillee 2014-08-26 17:22:21 +10:00
Родитель 3fc8bc592d
Коммит b478cb04f8
5 изменённых файлов: 70 добавлений и 31 удалений

Просмотреть файл

@ -56,6 +56,7 @@ A number of other tools are not shown — for example, Java can optionally be us
The whole toolchain is delivered in the :ref:`Emscripten SDK <sdk-download-and-install>`, and can be used on Linux, Windows or Mac OS X.
.. _about-emscripten-porting-code:
Porting code to use Emscripten
==================================

Просмотреть файл

@ -17,6 +17,7 @@ For concrete examples of using the filesystem API, see the automatic tests in ``
The reason for the filesystem API is that JavaScript is most often run in web browsers, which sandbox content and prevent it from accessing the local filesystem. Therefore emscripten simulates a filesystem so that C/C++ code can be written normally, as if there were direct access to files. Note: if you want to run in a shell environment using node without sandboxing, then you can let code directly access the local filesystem using NODEFS, see :ref:`Filesystem-API`.
.. todo:: HamishW - make sure we explain the implications of virtual file system, particularly with respect to when file ops can be called if we want to make sure that the virtual file system has completed loading. There is a faq on this.
Packaging Files
=========================

Просмотреть файл

@ -0,0 +1,33 @@
.. _api-limitations:
======================================
API Limitations (under-construction)
======================================
The browser environment and JavaScript are different to native environments and the standard C/C++. These differences impose some limitations on which native APIs can be called and how they are used. This section lists some of the more obvious limitations.
Networking
==========
Emscripten supports *libc* networking functions but you must limit yourself to asynchronous (non-blocking) operations. This is required because the underlying JavaScript networking functions are asynchronous.
File Systems
============
Emscripten supports *libc* file system functions and C/C++ code can be written in the normal way.
Code run in a :ref:`browser environment <Emscripten-Browser-Environment>` is sandboxed, and does not have access to the local file system. As a result, Emscripten creates a virtual file system that may be preloaded with data or linked to URLs for lazy loading. This affects when file system functions can be called and how a project is compiled. See the :ref:`Filesystem-Guide` for more more information.
Application Main Loop
=====================
The browser event model uses *co-operative multitasking* — each event has a "turn" to run, and must then return control to the browser event loop so that other events can be processed. A common cause of HTML pages hanging is JavaScript that does not complete and return control to the browser.
This can affect how an application using an infinte main loop is written. See :ref:`Emscripten-Browser-Environment` for more information.
Other APIs
==========
Support for other **portable** C/C++ code is :ref:`fairly comprehensive <about-emscripten-porting-code>`.

Просмотреть файл

@ -4,13 +4,14 @@
Code Portability and Limitations (under-construction)
=====================================================
This section is for .....
This section is for ....
.. toctree::
:maxdepth: 1
portability_guidelines
api_limitations
function_pointer_issues
browser_limitations.rst

Просмотреть файл

@ -4,49 +4,52 @@
Portability Guidelines (under-construction)
=========================================================
This article describes the types of code that are more difficult to compile, code which compiles but may run more slowly, and issues and limitations with specific APIs. Developers will find it useful for evaluating the effort to port and re-write code.
Emscripten can be used to compile almost any *portable* C++/C code to JavaScript.
Code that cannot be compiled
=============================
This section explains what types of code are non-portable (or more difficult to port), and what code can be compiled but will run slowly. Developers will find it useful for evaluating the effort to port and re-write code.
The following issues are fundamental difficulties. We can get around them by emulation in theory, but it would be very slow.
Non-portable code (code that cannot be compiled)
================================================
- Code that is multithreaded and uses shared state. JavaScript has threads - web workers - but they cannot share state, instead they pass messages.
- Nonportable code that relies on endianness is problematic. It can work with :ref:`typed-arrays-mode-2`, but it will not be portable!
- Nonportable code that relies on x86 alignment behavior. X86 allows unaligned reads and writes (so you can read a 16-bit value from a non-even address, i.e., which is only 8-bit aligned address, for example), but other archs do not: ARM will raise ``SIGILL``, and when Emscripten generates JavaScript you will get undefined behavior in this case. (If you build your code with ``SAFE_HEAP=1`` then you will get a clear runtime exception, see :ref:`Debugging`.
The following types of code are fundamentally non-portable, and would need to be re-written to work with Emscripten. While in theory it might be possible to workaround these issues using emulation, it would be very slow.
.. note:: The ``UNALIGNED_MEMORY`` code generation mode can support unaligned code like this, but it is very slow.
- Code that is multi-threaded and uses shared state. JavaScript has threads (web workers), but they cannot share state — instead they pass messages.
- Code that relies on endianness is problematic. It can work with :ref:`typed-arrays-mode-2`, but it will not be portable!
- Code that relies on x86 alignment behavior. X86 allows unaligned reads and writes (so for example you can read a 16-bit value from a non-even address), but other architectures do not (ARM will raise ``SIGILL``). For Emscripten-generated JavaScript the behavior is undefined. If you build your code with ``SAFE_HEAP=1`` then you will get a clear runtime exception, see :ref:`Debugging`.
.. note:: The `UNALIGNED_MEMORY <https://github.com/kripken/emscripten/blob/master/src/settings.js#L99>`_ code generation mode can support unaligned code like this, but it is very slow.
- Nonportable code that uses low-level features of the native environment, like native stack manipulation (e.g. in conjunction with setjmp/longjmp. We support normal setjmp/longjmp, but not with stack replacing etc.)
- Nonportable code that scans registers or the stack, for example to do conservative garbage collection. A variable in a register or on the stack may be held in a JavaScript local variable, which cannot be scanned. (However, you can do conservative scanning when there is no other code on the stack, e.g. from an iteration of the main event loop.)
- Code that uses low-level features of the native environment. For example, native stack manipulation in conjunction with ``setjmp``/``longjmp`` (we support normal ``setjmp``/``longjmp``, but not with stack replacing etc.)
- Code that scans registers or the stack. This won't work because a variable in a register or on the stack may be held in a JavaScript local variable (which cannot be scanned).
.. note:: Code of this type might be used for conservative garbage collection. You can do conservative scanning when there is no other code on the stack, e.g. from an iteration of the main event loop.
Code that compiles but might run slowly
=======================================
None of the issues here is a showstopper, but they might be slower than you expect. You probably don't need to worry about this stuff, but it might be useful to know about it.
.. note:: Understanding these issues can be helpful when optimising code.
- 64-bit ints. Bitwise operations on these are reasonable, but math (+, -, \*, /) is emulated, very slowly. JavaScript does not have native 64-bit ints so this is unavoidable.
- 32-bit multiplication that needs all 64 bits of precision must be emulated like 64-bit integer math (JavaScript doubles work fine up to ~52 bits). By default precise 32-bit multiplication is off as it makes a lot of common 32-bit code very slow, but if you need it you can enable it with ``-s PRECISE_I32_MUL=1``, see `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js#L121>`_ for more.
- 32-bit floats will end up as 64-bit doubles in JavaScript engines. That means they might be a little slower than expected, depending on your CPU.
- ``memcpy``/``memset`` works, but JavaScript engines don't optimize it very well. Native code will use SIMD on this, JavaScript engines will not - yet.
- Exceptions and ``longjmp``. In JavaScript such code generally makes the JavaScript engine turn off various optimizations. For that reason exceptions are turned off by default in ``-O1`` and above (to re-enable them, run *emcc* with ``-s DISABLE_EXCEPTION_CATCHING=0``). ``setjmp`` also prevents relooping around it.
The following types of code will compile, but may not run as fast as expected:
Code that should be avoided when easy to do
===========================================
- 64-bit ``int`` variables. Mathematical operations (+, -, \*, /) are slow because they are emulated (bitwise operations are reasonably fast). JavaScript does not have a native 64-bit ``int`` type so this is unavoidable.
- 32-bit multiplication that needs all 64 bits of precision is very slow because it is emulated:
Avoiding these kinds of code might be nice to do, to prevent warnings and to enable additional optimizations. But unless it is very easy for you to avoid them, just ignore this section.
- The JavaScript ``double`` type works fine up to ~52 bits.
- Precise 32-bit multiplication is disabled by default because it makes a lot of common 32-bit code very slow. It can be enabled by calling :ref:`emcc <emccdoc>` with ``-s PRECISE_I32_MUL=1`` (see `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js#L121>`_ for more information).
- 32-bit ``float`` variables will become 64-bit ``double`` variables in JavaScript engines. That means they might be a little slower than expected, depending on your CPU.
- ``memcpy``/``memset`` works, but JavaScript engines don't optimize it very well.
.. note:: Native code will use SIMD on this. JavaScript engines will not - yet.
- Exceptions and ``longjmp``. In JavaScript such code generally makes the JavaScript engine turn off various optimizations. For that reason exceptions are turned off by default in ``-O1`` and above. To re-enable them, run *emcc* with ``-s DISABLE_EXCEPTION_CATCHING=0`` (see `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js#L279>`_). ``setjmp`` also prevents relooping around it.
Code that should be avoided when easy to do so
==============================================
These types of code can trigger warnings and prevent certain optimizations. The code should be avoided, but only if it is very easy to do so:
- Unions. These will trigger ``SAFE_HEAP`` warnings (like *Valgrind*), and make the ``QUANTUM_SIZE=1`` :ref:`optimization <code-generation-modes-quantum-size>` impossible.
- Bitfields. Also ``SAFE_HEAP`` warnings.
- Reusing memory, that is, using the same allocated block of memory once for one kind of object, later for another. This prevents the ``QUANTUM_SIZE=1`` optimization.
Libraries
=========
Networking
----------
- Emscripten supports libc networking functions, but since JavaScript networking is asynchronous, you must limit yourself to asynchronous (nonblocking) operations.
- Bitfields. These will trigger ``SAFE_HEAP`` warnings.
- Reusing memory. Using the same allocated block of memory once for one kind of object and later for another prevents the ``QUANTUM_SIZE=1`` optimization.