Skip to content
Merged
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
54 changes: 53 additions & 1 deletion site/source/docs/porting/Debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,59 @@ Debug printouts can even execute arbitrary JavaScript. For example::
}


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 <bind.h>

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do this without embind (which is fairly heavyweight construct).

How about:

EMSCRIPTEN_KEEPALIVE
const char* getExceptionMessage(int exceptionPtr) {
    return reinterpret_cast<const char*>(exceptionPtr)->what());
}

Then have JS call UTF8ToString(getExceptionMessage(exception))?

Then you don't need EMSCRIPTEN_BINDINGS either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what sense is embind heavyweight? The doc seems to hint that it's reasonable, performance-wise.

This question isn't relevant to the PR - I'd just like to know, since I use embind throughout my project.

Copy link
Collaborator

@sbc100 sbc100 May 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to me to demonstrate one feature in isolation, when possible. In order to understand this code one has to also know about how embind work. It might lead the reader to think that embind is somehow essential to what is going on here.

IMHO, just returning a const char * would make the code here simpler, with less boilderplate. And there is no need to for the extra --bind link flag.

I think the reason I say heavyweight is because embind a whole bunch of C++ template magic that few people (myself included) have a good understanding of. I don't know how costly it is a runtime (maybe its not), but it is pretty complex at compile time. I'm not saying its bad or shouldn't be used, I'd just rather not use it when showing how other/simpler things work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel super strongly about not using embind here BTW. This is just my opinion. If you feel strongly that it helps here I'm not going block this PR. I do appreciate contributions to the documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried recreating the code in your way, but couldn't get it to run.
I'm sorry - I assume I'm doing something wrong, but I can't really dig into it right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think embind here is ok, if it makes things easier.

I can't seem to get this to work with embind, though. A full testcase might be helpful.


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

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.

.. 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'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But since the exception is a pointer won't it always appear here as a number (i32) , regardless of what one throws? What other type could this be here?

Copy link
Contributor Author

@Shachlan Shachlan May 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That depends on the code you wrap. I think that if you use embind you might also receive JS exceptions, and also - if your try clause wraps non-WASM code, you'll need some way to differentiate the errors.

AFAIK, actual exceptions thrown from WASM will always be number.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is assuming that no JS code throws numbers as exceptions I guess?

The implicit meaning of this function I guess is if (is_cxx_exception) getExceptionMessage() else ...

? Module.getExceptionMessage(exception)
: exception;
}


Disabling optimizations
=======================

Expand Down Expand Up @@ -285,4 +338,3 @@ Need help?
The :ref:`Emscripten Test Suite <emscripten-test-suite>` contains good examples of almost all functionality offered by Emscripten. If you have a problem, it is a good idea to search the suite to determine whether test code with similar behavior is able to run.

If you've tried the ideas here and you need more help, please :ref:`contact`.