I'm not sure if I understand the whole thread. For starters, BailErrorStrategy::recover in the first post takes two arguments and it looks you only provided one, making the second argument null automatically? Also I don't understand what you mean by "JS incarnation of C++ exceptions" either... Anyway, my comments for the last email are inline.
On Tue, Aug 22, 2023 at 9:26 AM 'Sam Clegg' via emscripten-discuss < [email protected]> wrote: > > > 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. > You can do that for Wasm exceptions by using the JS API <https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception> . An example of such code is in our JS library: https://github.com/emscripten-core/emscripten/blob/9bb02c0182bcfc32450ea15d5be69eab494042df/src/library_exceptions.js#L328-L344 This code does some string manipulation to make the stack trace tidy, but what you need for creating an exception and throwing is just these lines: ``` var e = new WebAssembly.Exception(getCppExceptionTag(), [ex], {traceStack: true}); throw e; ``` I'm not sure you can do that for the old way of Emscripten exceptions. > - 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)`. > I'm also not sure why embind should be involved. By the way, Wasm exceptions will not be represented as simple integer pointers in the JS world. They are WebAssembly.Exception <https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception> objects. > 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 > <https://groups.google.com/d/msgid/emscripten-discuss/CAL_va28LoU_7vRRJBNRPUyFxsCSC0X20ZDBfo2c4LfLpOgZ0qg%40mail.gmail.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/CALJpS1PE2s_D52y7AvyqTK-p6J%3DZOXPOcKss_5_-o18NYwmeAw%40mail.gmail.com.
