diff --git a/site/source/docs/porting/Debugging.rst b/site/source/docs/porting/Debugging.rst index 773c2148ce566..a4b872aec8829 100644 --- a/site/source/docs/porting/Debugging.rst +++ b/site/source/docs/porting/Debugging.rst @@ -157,60 +157,11 @@ See `Debugging WebAssembly with modern tools `_ 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 - - std::string getExceptionMessage(intptr_t exceptionPtr) { - return std::string(reinterpret_cast(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: diff --git a/site/source/docs/porting/exceptions.rst b/site/source/docs/porting/exceptions.rst index 5cb606e26c6ae..168336875eadf 100644 --- a/site/source/docs/porting/exceptions.rst +++ b/site/source/docs/porting/exceptions.rst @@ -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. @@ -113,11 +113,51 @@ property. For example: Stack traces within Wasm code are not supported in :ref:`JavaScipt-based exceptions `. -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 + `_ between Wasm + EH and Emscripten EH, on the reference counting. Using Exceptions and setjmp-longjmp Together diff --git a/test/test_core.py b/test/test_core.py index 7acfb7927d27f..930ca09f6cb0d 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -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());