Open devsnek opened 5 months ago
No, you aren't wrong or being dumb; when an exception is created implicitly via the wasm throw
instruction, there is no stack trace captured. This is to keep exception creation/throwing as fast as possible (some use cases want to use exceptions as a more general control-flow mechanism rather than having them be truly exceptional, and having to do a stack walk on every throw is problematic). But that means when the exception propagates out to JS there isn't the usual stack trace that you'd expect on an Error
object. It is possible to create an exception that has a stack trace via the JS API though. You can call out from wasm to JS and run something like the following:
let e = new WebAssembly.Exception(MyExceptionTag, [payload], {traceStack: true});
e.message = "An exception message";
throw e;
Where MyExceptionTag
is exported from the wasm module. This allows catching these exceptions (and rethrowing and extracting the payload) in wasm the same way you'd catch exceptions thrown with the throw
instruction (using the same tag). And when the exception propagates out from wasm to JS the WebAssembly.Exception
that comes out will have the message and stack trace. It's still observably different from an instance of Error
but it has the fields that you want. This is a bit of a compromise but works well, and it's what we do in emscripten.
Of course if you're calling out to JS, it's also possible to just actually create and throw real Error
objects. You can rethrow them in wasm, and if you import the JS exception tag into your module, you can catch them by tag and extract the Error object as the payload (it will appear as an externref
).
hmm this generally makes sense to me, though the problem I encountered is a bit different. I did not author the wasm, and the person who did doesn't understand why it created this exception either (interestingly, I think it was created using emscripten as well? But it doesn't export any tags or anything that JS could use to inspect the exception. I'm not super familiar with the details of dart to wasm compilation though, this was just something a user reported to me)
I get that there's a conceptual boundary formed by tags as capabilities, but I feel like the API is lacking in that there's no way to inspect these at all. Do I really need to like mod v8 or something to debug a wasm blob that is misbehaving?
If this is Dart code, then it probably wasn't created by Emscripten; dart has a different compiler. (I might be able to find out how that compiler uses exceptions though).
Is this situation materially different from JS code that throws something other than an Error
object? e.g. don't you also get an exception without a stack trace in that case?
(I might be able to find out how that compiler uses exceptions though)
Heh I won't ask you to debug random code for me.
Is this situation materially different from JS code that throws something other than an Error object? e.g. don't you also get an exception without a stack trace in that case?
You will not have a stack trace, correct, though many JS engines can helpfully show you the location of the throw
as long as it was not caught. I've also never had to debug code which does this in practice, and I would consider such code to be "extremely bad".
Perhaps this is more about how implementations should present exceptions, which is outside the control of wasm, but I would like to push for better information in the part we do have say over, the JS bindings.
(based on this issue: https://github.com/denoland/deno/issues/22861)
What is a human supposed to do with a
WebAssembly.Exception
instance? There seems to be no stack trace captured during wasm execution and any data this object does contain is not enumerable, so there is nothing one can do to extract any useful information from it?If I'm wrong or there are future plans or I'm generally being dumb please let me know...