-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposed exnref value type semantics #282
Comments
Can you walk me through why this is true on JS hosts? I wouldn't necessarily expect that a exception object already materialised on the JS side could be passed to Wasm as an |
So JS code can do things like: throw 'JS string primitive'; and wasm can catch that and receive an exnref: block $l (result exnref)
try (catch_all $l)
call $JS
end
end
;; exnref which contains a JS string primitive And in JS this thrown value doesn't have any identity or stack trace associated with it (AFAIK), it's simply just the primitive without any wrapper exception object. So that's why I believe we need to allow for However, other hosts could have (simpler) semantics that only objects in an exception class hierarchy can be thrown. So we wouldn't want to force those hosts to be able to convert anyref to exnref inside core wasm. It seems safe to allow the other direction though. |
Ah ok, I misunderstood. This makes sense, thanks! Do we expect that such an |
Unfortunately I think Per #280 (comment), my understanding had been that If Wasm code has the ability to convert an exnref into an externref (which for us is basically a |
@keithw Ah, good point. I did not know that wasm2c implemented |
I think that would be really tricky to specify, as tags are generative and so we'd need to have the tag for 'host values' that is importable. And then engines would need to know that there's a special tag that non-wasm exception objects all implicitly have. I think the |
@eqrion It's not GCed or ref-counted -- for wasm2c, |
I think we need to distinguish exnref values from host values thrown as exceptions. When you catch a host value, then the exnref you get conceptually carries that value, but it isn't the same as that value — I think of exnref as more like an instance of WebAssembly.Exception and the value is its arg. It may happen to work in JS to identify the two (and an implementation may do so), but I doubt it necessarily works for other embeddings to make that observable and allow converting between extern and exnref as if that maintained identity. If we want to allow Wasm to extract a JS value as an externref when catching a JS exception, then we should rather materialise JS exceptions with a special tag defined by the JS API. Then you can do:
With that there is no reason to allow converting exnref to externref or anyref, or to pass it to JS. If we don't, then I think an engine choosing to identify JS exn and its argument as mentioned above would become an unobservable optimisation, which seems preferable to hardwiring it into the semantics. |
@rossberg I think that could work, but I'll need to think about it more. I'm a bit nervous that long-term the implicit WebAssembly.Exception wrapping of JS values could become accidentally observable in a future extension. But maybe it's fine. @keithw Okay, that makes sense. In that case we should not have the conversion instructions I listed. |
We discussed exposing a special exception tag for JavaScript and allowing importing it (the payload would be an externref that represents the thrown object): #269 |
+1 on what @rossberg and @dschuff said. In the current JS API, we have So the drift of that is, I think To support catching of JS exceptions, #269 proposed a special "JS tag" so that the web engine can recognize it and treat it as a special case. So when wasm code uses |
Another reason in favor of having JS values auto-boxed in a WebAssembly.Exception is around null. In JS it's valid to throw/catch null:
While it also seems desirable to have This all may have been discussed before, I'm just catching up :) |
Now the #301 has landed I did want to briefly bring back up the question of passing exnrefs into JS via function return, global getters, etc. @rossberg mentioned there and above that we don't want exnref to be convertible to anyref or externref and I agree that makes sense. |
I think that would still be problematic, because ToWasmValue with target type exnref would then have to convert non-WA.Exception values to exnrefs with the JS tag. But doing so it wouldn't be able to distinguish a WA.Exception that was originally an exnref (and hence needs to be converted back into one, using the original tag and throw context) from a random object manually created via So AFAICS, this would still lead to the conflation of different value domains: exnrefs and their payloads. The former represent thrown values, including the context of the throw, not the values themselves. Unless you somehow want to treat manually created WA.Exception objects as actual exnrefs with some dummy throw context. But I'm not convinced that's desirable or useful. (Note that this conflation does not occur when merely throwing a manual WA.Exception, because that explicitly turns it into a thrown value, producing an actual throw context.) |
I think the issues here have been resolved and the JS API spec now reflects what we discussed here. Let's open specific new issues if there's anything new. |
I don't believe this was discussed elsewhere, apologies if I missed it.
Here's a proposal for the semantics of the new exnref value type.
catch
orcatch_all
may receiveToWebAssemblyValue(value, 'exnref')
succeeds for any value (like externref)ToJSValue(value, 'exnref')
succeeds for any value (like externref)extern.convert_exn
instruction for getting an externref from an exnrefany.convert_exn
instruction for getting an anyref from an exnrefnoexn
heap type to mirror the other bottom typesnullexnref
alias for(ref null noexn)
ref.cast exnref/nullexnref
are valid instructions similar, but do very little like in the externref hierarchy.Note, there is no
exn.convert_any
orexn.convert_extern
as we don't want to assume in core wasm thatexnref
can hold any host value. That's true on JS hosts though, which is why the JS-API allows conversions on the boundary.Did I miss anything?
There is a world where we do something more conservative and don't allow exnref in
ToWebAssemblyValue
ToJSValue
or introduce the conversion instructions. But I don't think they are much work, and would be useful.The text was updated successfully, but these errors were encountered: