-
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
[js-api] Add stack trace support and preserve identity of JS exception values passing through WebAssembly. #218
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Sorry for the late reply; I was OOO.
Sorry for the many questions; I am not very familiar with the JS API text.
Other questions:
-
We have sections called "Call an exported function" and "Create a host function". Does "Call an exported function" happen on the JS side and does "Create a host function" on the Wasm side?
-
Another question about the existing issue:
Issue: Should it be possible for `catch <JS-exception-tag>` to extract the payload from an exception with this tag?
Can we consider this resolved given that we have an JS API that can create WebAssembly.Exception
?
- Does this also address Preserve identity of exceptions from JS when passing through wasm #189, or does it need to be separately addressed?
However, I'm realizing I don't fully understand how |
Thanks for making me think through #189; this PR now fixes that as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Create a new exported function
- Call an exported function
- Create a host function
- Run a host function
We only handle exceptions in 2 and 3. I think I don't have a clear concept of the difference between "create" and "call/run"; the steps look kind of similar to me. Why do we only need to handle "call" in case of an exported function and "create" in case of a host function?
1. Let |payload| be [=ToWebAssemblyValue=](|v|, [=externref=]). | ||
1. [=WebAssembly/Throw=] with |type| and |payload|. | ||
1. Let |payload| be « ». | ||
1. Let |opaqueData| be [=ToWebAssemblyValue=](|v|, [=externref=]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks this wraps the whole value itself as opaqueData
, correct? Where does the stack trace belong then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stack trace just stays in a slot on the Exception
JS object
1. Let |type| be the [=JavaScript exception tag=]. | ||
1. Let |payload| be [=ToWebAssemblyValue=](|v|, [=externref=]). | ||
1. [=WebAssembly/Throw=] with |type| and |payload|. | ||
1. Let |payload| be « ». |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not need to handle |v|.\[[Stack]]
in here and also in line 1106-1107?
1. If |exntag| is the [=JavaScript exception tag=], then | ||
1. Let « [=ref.extern=] |externaddr| » be |payload|. | ||
1. If |ret| is exception |exntag| |payload| |opaqueData|, then | ||
1. If |opaqueData| is not [=ref.null=] [=externref=], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case is this ref.null
? When it is thrown from wasm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The split between call/run/create is not particularly meaningful. In the "host function" case, it exists because there's no well-defined try-finally construct in prose, so "run a host function" exists as an algorithm you can early-return from if there's an exception, and then "create a host function" can put the (exception-or-normal) result in a variable. I think we could merge "call an Exported Function" into "a new Exported function" now that ECMAScript uses abstract closures for CreateBuiltinFunction (tc39/ecma262#1894); the current split predates that (WebAssembly/spec@d15cabb).
1. If |exntag| is the [=JavaScript exception tag=], then | ||
1. Let « [=ref.extern=] |externaddr| » be |payload|. | ||
1. If |ret| is exception |exntag| |payload| |opaqueData|, then | ||
1. If |opaqueData| is not [=ref.null=] [=externref=], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed.
1. Let |payload| be [=ToWebAssemblyValue=](|v|, [=externref=]). | ||
1. [=WebAssembly/Throw=] with |type| and |payload|. | ||
1. Let |payload| be « ». | ||
1. Let |opaqueData| be [=ToWebAssemblyValue=](|v|, [=externref=]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stack trace just stays in a slot on the Exception
JS object
@dschuff Do you have any comments? |
Thinking about the exception identity here... IIUC:
When an exception is originated from JS:
One thing I can't recall from our discussion: when exceptions propagate into wasm (i.e. where we say "To throw" in section 4.7.3) it says "invoke the catch block with payload and opaqueData". What does that mean? Which of the payload and/or opaqueData gets actually pushed onto the wasm value stack in the catch block? |
All this matches my understanding.
I believe the goal is:
I think it would be best if this was clarified in the core spec, but I haven't had time to dig into where exactly that would go. |
The current formal reduction rule for
So this does a fresh throw, which I think can't be helped in the formal spec because formal spec doesn't have a concept of opaque data. The core spec only knows about the tag and the payload, so there's no other way to express the functionality anyway. But should we say something about the core spec's |
@Ms2ger Gentle ping for my latest question :) |
Indeed, according to the current formal spec, I would have to think of a different way to address opaque data in the core spec, if that is even necessary. |
Apologies for the delay - I haven't had much wasm time recently. I'd prefer landing this PR as is, and I'll work with @ioannad to update the core spec to clarify how the opaque data is passed through. |
The core spec doesn't have any notion of exception identity – we removed that intentionally, otherwise we could have kept So with the current state of affairs, I think it rather ought to be hand-waved in the JS API spec somehow. (Of course, I'd be all for reintroducing exnref properly, which would allow to significantly simplify the proposal and solve the known expressiveness problems. :) ) |
I'm going to merge this as is, as it's a significant improvement over the status quo, and I'll file an issue on either making the changes to the core spec or hand-waving in the js-api spec. |
This basically does the "handwaving" we discussed in WebAssembly#218. I think adding a concept of a backing store through backdoors in the core spec is not very feasible, so this is what we can do practically at this point. Hopefully resolves WebAssembly#242.
Fixes #189.
Fixes #201.