Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 2 additions & 51 deletions site/source/docs/porting/Debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,60 +157,11 @@ See `Debugging WebAssembly with modern tools
<https://developer.chrome.com/blog/wasm-debugging-2020/>`_ for the details.


.. _handling-c-exceptions-from-javascript:

Handling C++ exceptions from JavaScript
Handling C++ Exceptions from JavaScript
=======================================

C++ exceptions are thrown from WebAssembly using exception pointers, which means
that try/catch/finally blocks in JavaScript will only receive a number, which
represents a pointer into linear memory. In order to get the exception message,
the user will need to create some WASM code which will extract the meaning from
the exception. In the example code below we created a function that receives the
address of a ``std::exception``, and by casting the pointer
returns the ``what`` function call result.

.. code-block:: cpp

#include <emscripten/bind.h>

std::string getExceptionMessage(intptr_t exceptionPtr) {
return std::string(reinterpret_cast<std::exception *>(exceptionPtr)->what());
}

EMSCRIPTEN_BINDINGS(Bindings) {
emscripten::function("getExceptionMessage", &getExceptionMessage);
};

This requires using the linker flags ``-lembind -sEXPORT_EXCEPTION_HANDLING_HELPERS``.
Once such a function has been created, exception handling code in javascript
can call it when receiving an exception from WASM. Here the function is used
in order to log the thrown exception.
See :ref:`handling-c-exceptions-from-javascript`.

.. code-block:: javascript

try {
... // some code that calls WebAssembly
} catch (exception) {
console.error(Module.getExceptionMessage(exception));
} finally {
...
}

It's important to notice that this example code will work only for thrown
statically allocated exceptions. If your code throws other objects, such as
strings or dynamically allocated exceptions, the handling code will need to
take that into account. For example, if your code needs to handle both native
C++ exceptions and JavaScript exceptions you could use the following code to
distinguish between them:

.. code-block:: javascript

function getExceptionMessage(exception) {
return typeof exception === 'number'
? Module.getExceptionMessage(exception)
: exception;
}

.. _debugging-emscripten-specific-issues:

Expand Down
50 changes: 45 additions & 5 deletions site/source/docs/porting/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ If you want to opt-in, you have two following options.

.. _javascript-based-exception-support:

JavaScript-based Exception Support
==================================
Emscripten (JavaScript-based) Exception Support
===============================================

First, you can enable exceptions via Emscripten's JavaScript-based support. To
enable it, pass ``-fexceptions`` at both compile time and link time.
Expand Down Expand Up @@ -113,11 +113,51 @@ property. For example:
Stack traces within Wasm code are not supported in :ref:`JavaScipt-based
exceptions <javascript-based-exception-support>`.

Exception Messages
------------------

.. _handling-c-exceptions-from-javascript:

Handling C++ Exceptions from JavaScript
---------------------------------------

You can also catch and examine the type and the message of C++ exceptions from
JavaScript. See :ref:`handling-c-exceptions-from-javascript`.
JavaScript, in case they inherit from ``std::exception`` and thus have ``what``
method.

``getExceptionMessage`` returns a list of two strings: ``[type, message]``. the
``message`` is the result of calling ``what`` method in case the exception is a
subclass of ``std::exception``. Otherwise it will be just an empty string.

.. code-block:: javascript

try {
... // some code that calls WebAssembly
} catch (e) {
console.log(getExceptionMessage(e).toString());
} finally {
...
}

In case the thrown value is an integer 3, this will print ``int,``, because the
message part is empty. If the thrown value is an instance of ``MyException``
that is a subclass of ``std::exception`` and its ``what`` message is ``My
exception thrown``, this code will print ``MyException,My exception thrown``.

To use this function, you need to pass ``-sEXPORT_EXCEPTION_HANDLING_HELPERS``
to the options. You need to enable either of Emscripten EH or Wasm EH to use
this option.

.. note:: If you catch a Wasm exception and do not rethrow it, you need to free
the storage associated with the exception in JS using
``decrementExceptionRefcount`` method because the exception
catching code in Wasm does not have a chance to free it. But currently due to
an implementation issue that Wasm EH and Emscripten (JS-based) EH, you need
to call incrementExceptionRefcount additionally in case of Emscripten EH. See
https://github.com/emscripten-core/emscripten/issues/17115 for details and a
code example.

.. todo:: Fix the above-mentinoed `inconsistency
<https://github.com/emscripten-core/emscripten/issues/17115>`_ between Wasm
EH and Emscripten EH, on the reference counting.


Using Exceptions and setjmp-longjmp Together
Expand Down
1 change: 1 addition & 0 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,7 @@ class myexception : public exception {
// Emscripten EH sets the refcount to 0 when throwing, and
// increase it in __cxa_begin_catch, and decrease it in
// __cxa_end_catch. Fix this inconsistency later.
// https://github.com/emscripten-core/emscripten/issues/17115
incrementExceptionRefcount(p);
#endif
console.log(getExceptionMessage(p).toString());
Expand Down