>
> Taking a quick look at rethrow_exception, it looks like it calls `terminate`
> if the `ptr` is NULL:
>
> https://github.com/emscripten-core/emscripten/blob/097290ded2746c6ba703d556fd53b23e5aef760a/system/lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp#L66-L71
>
> Can you trace the value of the `std::exception_ptr` you are trying to rethrow
> to confirm?
That was spot on Sam! The error is thrown in JS, so calling
`std::current_exception()` in C++ returns a null ptr. What I do now is to
forward the thrown exception from JS (which is one of the C++ exceptions) and
call std::make_exception_ptr to convert it to an exception pointer (to create a
nested exception).
>
> Regarding handling C++ exceptions in JS, I think you will always need to do
> things like getExceptionMessage to unpack information if all you have is a
> thrown object from C++.
Well, the thrown error has its name set to the C++ exception, so what I do now
is:
private isCancellationException(e: Error): boolean {
return e.name === "std::__nested<antlr4::ParseCancellationException>";
}
Not really elegant, nor type safe, but it works.
>
> Can you explain what you mean by "if I throw a C++ exception in its JS
> incarnation".. what is a JS incarnation?
Sure. There are 4 ways you can throw an exception/error with wasm:
- throw JSError in JS
- throw C++ exception in C++
- throw C++ exception in JS
- throw a JS error in C++ (I believe, never tried that)
To throw a C++ exception in JS that exception must be bound as usual with
embind (and that thrown JS error is the JS incarnation of the C++ exception).
When you get an instance of a normal C++ class in JS, it represents such an
embind/emval object (class handle). Not so for a C++ exception thrown in C++
but catched in JS. Check this out:
This is the JS object of the C++ exception thrown in C++:
std::__nested<antlr4::ParseCancellationException>\n at ___resumeException
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:1328:25)\n
at antlr4::BailErrorStrategy::recover(antlr4::Parser*, std::exception_ptr)
(wasm://wasm/0507610a:wasm-function[2254]:0x414cb)\n at invoke_viii
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:7667:29)\n
at antlr4::BailErrorStrategy::recover(antlr4::Parser*,
antlr4::RecognitionException*)
(wasm://wasm/0507610a:wasm-function[2257]:0x4161d)\n at
emscripten::internal::MethodInvoker<void
(antlr4::BailErrorStrategy::*)(antlr4::Parser*, antlr4::RecognitionException*),
void, antlr4::BailErrorStrategy*, antlr4::Parser*,
antlr4::RecognitionException*>::invoke(void (antlr4::BailErrorStrategy::*
const&)(antlr4::Parser*, antlr4::RecognitionException*),
antlr4::BailErrorStrategy*, antlr4::Parser*, antlr4::RecognitionException*)
(wasm://wasm/0507610a:wasm-function[205]:0xb1a1)\n at ClassHandle.BailE… …
excPtr:
4098424
name:
'std::__nested<antlr4::ParseCancellationException>'
message:
''
stack:
'std::__nested<antlr4::ParseCancellationException>\n at ___resumeException
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:1328:25)\n
<> at antlr4::BailErrorStrategy::recover(antlr4::Parser*,
std::exception_ptr) (wasm://wasm/0507610a:wasm-function[2254]:0x414cb)\n <>
at invoke_viii
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:7667:29)\n
<> at antlr4::BailErrorStrategy::recover(antlr4::Parser*,
antlr4::RecognitionException*)
(wasm://wasm…r4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:12448:40)\n
<> at MySQLParser.selectStatement
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:12222:30)\n
<> at MySQLParser.simpleStatement
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:3283:30)\n
<> at MySQLParser.query
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:3140:46
<>)'
[[Prototype]]:
EmscriptenEH
while the C++ exception, thrown in JS looks like this:
ClassHandle {$$: {…}}
$$:
{ptrType: RegisteredPointer, ptr: 4069744, count: {…}}
[[Prototype]]:
ClassHandle
The call stack for the first case is:
std::__nested<antlr4::ParseCancellationException>
at ___resumeException
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:1328:25)
at antlr4::BailErrorStrategy::recover(antlr4::Parser*, std::exception_ptr)
(wasm://wasm/0507610a:wasm-function[2254]:0x414cb)
at invoke_viii
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:7667:29)
at antlr4::BailErrorStrategy::recover(antlr4::Parser*,
antlr4::RecognitionException*)
(wasm://wasm/0507610a:wasm-function[2257]:0x4161d)
at emscripten::internal::MethodInvoker<void
(antlr4::BailErrorStrategy::*)(antlr4::Parser*, antlr4::RecognitionException*),
void, antlr4::BailErrorStrategy*, antlr4::Parser*,
antlr4::RecognitionException*>::invoke(void (antlr4::BailErrorStrategy::*
const&)(antlr4::Parser*, antlr4::RecognitionException*),
antlr4::BailErrorStrategy*, antlr4::Parser*, antlr4::RecognitionException*)
(wasm://wasm/0507610a:wasm-function[205]:0xb1a1)
at ClassHandle.BailErrorStrategy$recover [as recover] (eval at newFunc
(file:///Volumes/Extern/Work/projects/antlr4wasm/wasm/antlr4-runtime-wasm.js:5544:27),
<anonymous>:11:1)
at MySQLParser.queryExpression
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:12448:40)
at MySQLParser.selectStatement
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:12222:30)
at MySQLParser.simpleStatement
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:3283:30)
at MySQLParser.query
(file:///Volumes/Extern/Work/projects/antlr4wasm/benchmarks/mysql/generated/TypeScript/MySQLParser.ts:3140:46)
{excPtr: 4098424'}
The class MySQLParser is a JS file (TS actually, but anyway). During a parse
run it creates an error (which is a bound C++ exception) and throws it. It also
catches it and forwards it to C++ (the call to `recover`). This function now
throws a nested C++ exception, which is then catched in the outer code that
started the parser run.
>
> When you talk of ` $$` and `class handle` and you talking about embind/emval
> objects?
The JS operator `instanceof` only works for the second form (embind/emval
object), not the first one, which must be some special object type I have not
seen before in normal execution.
Mike
--
www.soft-gems.net
--
You received this message because you are subscribed to the Google Groups
"emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/emscripten-discuss/FC886282-090A-4B9B-9EDD-9D09D82BF6E3%40googlemail.com.