Remove rethrow #127
Description
With the new change, every program with rethrow
is semantically equivalent to a program without rethrow
with minimal changes. In the meanwhile, rethrow
is a rather complicated instruction due to its context-sensitivity. It complicates the spec by requiring catch
blocks to be tracked on the stack. It complicates implementations by requiring (streaming) engines to keep a copy of the exception's payload on the stack until the end of the catch is reached in case it gets rethrown. So removing rethrow
will not lose any functionality and will simplify the spec and improve implementations. It might also make transforming programs easier because there will be no need to preserve the location of rethrow
instructions within matching catch
blocks (or to reindex them to match changes to nesting catch
blocks).
The primary argument for rethrow
has involved stack traces. Stack tracing should not be done implicitly (at least in production mode) because it can be quite costly, especially for languages that use exceptions as dynamic control throw rather than just for errors. As for debug mode, there are other ways to trace stacks, including techniques that will work just as well without rethrow
.
As an example of exceptions as non-error control flow, there are two ways to implement for each
loops (using iterators, not generators, so I'm not going into algebraic effects here). One is to check if the iterator has more elements before each iteration of the loop. The other is to just keep getting more elements from the iterator until it throws a "no more elements" exception. Provided throwing an exception is cheap, the latter can outperform the former even in very small loops because it eliminates an interface-method call in each iteration.
This latter implementation of for each
illustrates how to effectively use exceptional control flow in library and language design. But its performance is very sensitive to the time it takes to throw exceptions. As an example, Section 9.2 of this paper found disabling stack tracing in the JVM made one of its exception-intensive libraries implementing regex parsing 6x faster (it unfortunately only measures one library).
Hopefully this 6x difference illustrates that, debug-mode aside, if we want people targeting WebAssembly to be able to reasonably account for performance tradeoffs in devising their compilation strategy, then WebAssembly engines need to be consistent about whether/how they perform stack tracing. And if we want this proposal to be a good target for exception-intensive programs/languages, then engines should not be implicitly performing stack tracing. If they're not, then rethrow
serves no utility.