> 
> 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 emscripten-discuss+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/emscripten-discuss/FC886282-090A-4B9B-9EDD-9D09D82BF6E3%40googlemail.com.

Reply via email to