On Tue, Aug 22, 2023 at 1:56 AM 'Mike Lischke' via emscripten-discuss < [email protected]> wrote:
> > 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 > My JSError do you mean something that is the result of calling `new Error` in JS? I don't think that can or should interact at all with the C++ exception handling mechanism. I see them as two orthogonal systems and trying to mix them or conflate them is likely to lead to trouble. > - throw C++ exception in C++ > This should clearly work. > - throw C++ exception in JS > I don't think it possible (or should be possible) to use a JS `throw` statement to throw C++ exception.. C++ exceptions must be thrown by the native `__cxa_throw` mechanism. In order words even if you have a handle to C++ object you want to throw, I believe the only way to throw is to call back into native code to perform a C++ throw. I could be wrong about this though.. @Heejin Ahn <[email protected]> can probably say more on this. - throw a JS error in C++ (I believe, never tried that) > IIRC would just be throwing C++ object that happened to be a val that pointed to JS object.. which I think should work fine. > 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). > I don't see why embind would need to be involved necessarily. Not all programs use embind, and its possible to refer to C++ object via simple pointers in JS. If you have a simple pointer to C++ object I don't think there is anything stopping you from just doing `throw ptr` in JS. However, as I say above that is not that same as throwing in C++.. and what you would really want to do is callback into native code. e.g. `_throw_in_cpp(ptr)`. 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 > <https://groups.google.com/d/msgid/emscripten-discuss/FC886282-090A-4B9B-9EDD-9D09D82BF6E3%40googlemail.com?utm_medium=email&utm_source=footer> > . > -- 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/CAL_va28LoU_7vRRJBNRPUyFxsCSC0X20ZDBfo2c4LfLpOgZ0qg%40mail.gmail.com.
