On Tue, Aug 20, 2013 at 9:00 PM, William ML Leslie <
[email protected]> wrote:

> In the compiler, you know you're compiling an except or finally block.
>  So what is special about this code - what does it have to look like?
>
> There are three possible forms of control flow out of a handler:  we
> exit with the current exception, we exit with a new exception, and we
> exit having handled the exception.  These cover both finally and
> blocks that conditionally re-raise the original exception (hopefully,
> with the original traceback if it fails).
>

>From a code generation perspective, that's only two cases: exit having
handled or exit raising. You need to generate a new exception object if you
are raising rather than re-raising, but the raise itself looks the same in
either case.

The other complication here is whether you use the "inner exception"
mechanism when you raise. Among other things, that allows the entire stack
trace chain to be reproduced later.


> When we have handled the
> exception, we know the target, can set the stack pointer and jump
> directly to the relevant code - no need to indirect through the raise
> trampoline.  It's the finally case (or equivalently, reraise) that
> will need to be smart about determining the next handler up the chain;
> it's here that we expect to have a frame that knows how to find the
> next handler and set up its arguments appropriately.
>

In the presence of a finally block it isn't quite that simple. Yes, you
know the target PC in the exception handler if you have handled the
exception, but you still need to run the finally block, and that's common
code. The simple solution in *either* case is to store the target PC to a
temporary and then have the finally block perform a branch indirect.
Recovering the intended SP can be handled similarly.


> Now, aside from concerns around control flow, in order to run a
> handler outside its original stack, you need to be very careful about
> how you generate the code.  For example, accessing local variables in
> the original frame require that you indirect against the original
> stack pointer, which means you actually need to obtain it, either by
> walking the stack, or by pushing it together with the handler target
> onto a block stack.
>

Sure. But this just isn't that hard. The only thing that's special about
the stack is that it has an unusual relationship with the CALL, RETURN,
PUSH, and POP instructions - and that only on some architectures.
Otherwise, a stack frame is just a structure like any structure. The kind
of code generation you are talking about is very commonly required in
languages that permit nested procedures. The mechanism typically used to
handle this is sometimes know as a "display". Any compiler that handles one
of the PASCAL variants already has support for this. The support needed is
also very similar to what gets used in closure conversion.


> While I think this is a reasonable way to implement exceptions, you do
> need to consider if storing that sort of additional detail and
> introducing indirections to otherwise local variables into your
> exception handlers is a cost you are willing to pay in bitc for its
> default exception mechanism.  It's one option, but it's not the
> obvious one; other mechanisms such as transitive static or dynamic
> inference as to whether or not a stack trace will ever need to be
> printed from the current raise may impose lower runtime overhead.
>

So yes, it has a cost, but I don't think that's such a big issue for
exception handler code. As to inference about the stack trace, that's a
fine idea, but I think it's an orthogonal issue. Though now that I think
about it static inference isn't really possible in the presence of dynamic
linking or dynamic loading.


> Additionally, depending on how hackers manage "resources" (especially
> the type with explicit dynamic extent, like 'with' blocks, linear
> types, and stack-allocated RAII objects), the finally case may become
> particularly descriptive of how fast we can unwind the stack and the
> real 'performance' of the exception mechanism.


I agree, except that I wouldn't characterize this as "performance of the
exception mechanism". The type of unwinding and reclaiming you are talking
about would be needed in an error-handling style of system as well.


Jonathan
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to