-
Notifications
You must be signed in to change notification settings - Fork 36
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
Restore rethrow's immediate argument? #126
Comments
This seems odd to me. Different languages have different semantics for throwing exceptions in general, including rethrow. |
I'm not exactly sure what this means. Do you mean, can we use I think having two kinds of throwing instruction, currently Restoring the immediate means whether we should allow |
It's hard to discuss tradeoffs between design alternatives for a feature without known use cases for the feature. I think what @fgmccabe is noting is that, when you consider the potential use cases, you don't find much consistency. For example, Java, Python, and C# each have different semantics for rethrowing exceptions. But maybe those are not meant to line up with the |
I read the justification for including this that @rossberg posted, and I agree that making nesting of handlers easier/possible is a natural choice from the language semantics point of view. However I'm a bit concerned about the complication for implementing this, as I think the immediate argument for |
Is it correct that rethrow-with-immediate can always be emulated by adding a branch out to the correct |
Don't you need to keep this exception stack anyway even without the immediate argument? As @tlively said, we can still go from the inner catch scope to outer catch scope (by a branch or fallthrough) and rethrow the outer exception from there. |
I think so.
For C++ we lack use cases, but for languages that use |
That comment does not refer to any actual language. We currently have zero use cases. Python and C# both modify their exceptions when they rethrow them, and so they would have to implement their rethrow with Without knowing what |
@aheejin Thanks, I think you're right about this, nevermind my comment about |
@aheejin, I have a really dumb question: how did you implement a correct semantics of |
@rossberg Sorry, I think I said something confusing. Our C++ implementation currently uses
What I tried to say was we don't use |
@aheejin, that makes sense, thanks for the clarification. So this seems to imply that we clearly need |
Notice that this is "rethrowing" an exception with a known tag and available payload. |
Without
I think we have a very clear use case for |
For me, the answer depends on what rethrow means and how rethrow will be used. That said, it does sound like there's reason to believe that every hypothetical use does not need an immediate, so I'm personally fine with you closing the issue with that answer. |
Without two-phase unwinding, embedding stack traces or other info in exceptions is a way that we can provide some info. We didn't specify which info we should provide in the spec to maximize each engine's leeway according to their necessity though. We are currently using it, and I think this is sufficient to attest to the "Is there a use case" argument.
Not sure exactly what you mean. The objective here is to decide whether we should restore the immediate back or not, and if we decide we should, propose to the CG meeting about the change. Have we made the decision? |
To implement destructors or finally in a heterogeneous language environment you need to be able to rethrow exceptions whose tag you do not know. For example, when C++-Wasm calls back into JS and JS throws. |
@rossberg That has been addressed by
@aheejin An engine can have a global variable for the stack trace. If a function throws an exception, then the engine can initialize this variable to the empty stack. As it searches for a We also want to consider that there are uses of the exception handling proposal that do not want you collecting stack traces because it is a waste of time, i.e. they are using it for dynamic control flow and know the thrown exception will be caught. Applications that do want a stack trace can always explicitly put one into the payload. I prefer this approach because it takes guesswork out of engines (should the engine trace the stack or not? answer depends on the application). |
@RossTate I answered your "is there a use case?" argument. Given that we implemented it, are using it, and haven't had a major problem with it, I don't think every single aspect of the existing spec should also satisfy "Is this the only way to do this thing?" question. |
My impression is that there's no need for an immediate in any hypothetical use. @rossberg is I think the only person we're waiting for updated thoughts from. |
My point still stands I believe. Implicit naming of nestable constructs is a basic structural design mistake. I gave an example. What would be the advantage of artificially crippling the instruction that way? |
Note that specifying exception to rethrow was capable using |
@rossberg Not having an index makes the instruction size smaller for the extremely common case. And having an index would be redundant because it can easily be encoded through existing constructs. |
Barely. |
In this thread you seem to be simultaneously arguing that the entire instruction is useless and that it is gonna be extremely common. I have a hard time reconciling both these claims. |
I believe the use cases for the instruction could just as easily be served by
If that's the case, then that suggests we should have Taking things a step further, languages like Python modify the exception as it goes up the stack. Rather than having Putting this all together, the pair of |
@RossTate Umm... Can we please not turn everything upside down again and bikeshed new instructions two days after we passed a new spec...? Brainstorming and bikeshedding language design can be fun, but I think we really need to settle down and ship things. Also, I think the approach when designing new instructions and changing already existing and implemented instructions should be different. We can't spend endless time bikeshedding things, and I think changing existing things require a stronger argument than designing things first time unless there's a clear problem that people agree on. (By the way, usage or |
My guess is that |
@binji As I said in #126 (comment), it's not rare at all; currently it's used all the time. The usage 2 will be replaced by And both 1 and 2 are not rethrowing but actually resuming. (In single-phase they are effectively the same.) C++ does not use |
Sorry, I mean rare compared to the total number of instructions. But if you have data that would be useful -- what percentage of the instructions in the code section for a medium-sized module are |
@binji I just checked a single file that contains ~35000 instructions and |
Clarification request: which of these programs are supposed to be equivalent?
|
@RossTate 2 and 3 will have the same throwing site. The two programs are different still, so not sure what the definition of equivalence is though. |
Equivalence informs tools which program transformations/optimizations are valid. Inlining also changes throwing sites and stack traces. So it seems like either inlining functions that might throw exceptions is an invalid optimization, or the above three programs are equivalent. If the three programs are equivalent, then every program with |
Stack traces are usually used for debugging without optimizations turned on. In your example two throwing sites are very close, but if rethrowing happens later in another caller up in the call stack, the stack traces will be vastly different. Your argument that inlining can make things the same is like, all stack traces that ever exist can be the same if all functions are inlined into And as I said, I think now is the time to actually make things work and ship things. We made a new spec two days ago. We can still consider changes, but I think they should satisfy one of these:
|
Like @RossTate, I'm not totally convinced that Given all that, I think a reasonable course of action would be to keep |
I feel we need to be explicit about the expectations on stack tracing. When I asked language implementers for advice on exception handling, a common sentiment was to not have stack tracing as a default. It apparently substantially slows down the use of exceptions for dynamic control flow. Most implementations of efficient dynamic control flow either use two-phase approaches (so that they can collect the stack only after they find out the exception is uncaught) or do not collect the stack trace (except for possibly keeping the portion of the stack above the last handler/unwinder in tact). As an example, for stack switching we think it makes sense to build on this proposal as it provides a mechanism for dynamic control flow. But it would be problematic if doing so causes a stack trace every time, an operation that could easily dominate the time of the stack switch itself. Plus, as I pointed out above, there are other ways to build and track a stack trace than putting it in the exception payload. The technique I mentioned above would give the same stack trace for all three programs (that I believe should be considered equivalent). Another is for the application to make the stack trace an explicit part of the payload (as an |
I think I'm repeating myself at this point, so I'll summarize my answers here one more time:
And one more thing... this issue was about the immediate argument and I hoped this issue to focus on that. Whether we need |
Fair request. I've moved discussion of whether to have |
* [interpreter] Simplify zero-len and drop semantics * Update overview * [spec] Change drop semantics * [spec] Forgot to adjust prose for *.init ops * [test] Update generated tests for OOBs and dropping changes (WebAssembly#131)
After the spec change in WebAssembly#126, byte copying order is not observable.
We left out
rethrow
s immediate argument in the last CG meeting's poll because we weren't sure about the use cases, but @rossberg suggested one in #125 (comment).I think having this functionality is in general good as long as there exist languages that
rethrow
instruction for their rethrowing functionality, i.e., want to relay some auxiliary info when rethrowingWhat do you think?
The text was updated successfully, but these errors were encountered: