On Mon, Aug 12, 2013 at 10:27 PM, David Jeske <[email protected]> wrote:

> On Mon, Aug 12, 2013 at 1:35 AM, Bennie Kloosteman <[email protected]>wrote:
>
>> Yes, though I see no reason why this should not be true for exception
>> handlers when the Liskov implementation technique is used.
>>
>
> @Shap - After some digging, I'm now confused about this comment. Were you
> talking about the original CLU exception mechanism?
>
>
> http://www-public.it-sudparis.eu/~gibson/Teaching/CSC7322/ReadingMaterial/LiskovSnyder79.pdf
>
> As of that paper they only allowed one-level exception signaling, which
> sounds to me like a form of structured return value.
>

So first, you shouldn't take the implementation that is sketched in that
paper too literally. Yes, structured return values *could* be used, and
that's actually a very good way to reason formally about exception handling
if you don't want to get trapped in the view that exceptions are effects,
but no, that isn't the typical implementation.

The problem with using a structured return value is that the compiler must
emit a test-and-dispatch at every call site. This is more work than you
need to do, since there are fewer catch points than there are procedure
calls. There are several better implementations.

First, note that most calling conventions specify a register to be used for
procedure return values. In the normal (successful) return case this will
hold a value matching the return type of the function (I'm ignoring struct
return here). In the exceptional case, no normal return value is actually
returned, and the same register can be used to return the exception value.
So that's how the *value* gets returned, now what about the receiver
discriminating what happened?

The simplest way to do that is to have (in effect) two return PCs. One used
for normal return and the other used for exceptional return. The act of
returning to the exception return PC subsumes the type tag check that would
otherwise be needed at the point of return.

There are several ways to obtain that alternate return PC:

1. Store it on the call stack explicitly at the point of call.
2. Implement a lookup table that maps from normal return PCs to exceptional
return PCs.
3. Define the exceptional return address to exist at a known constant
offset from the normal return address.
4. Store the exceptional return address in a thread-local variable whenever
a catch block is entered. Look it up there when performing an exceptional
return. In this design the catch block setup records the enclosing catch
block PC, thereby implementing a stack of catch blocks.

In practice, options (2) and (4) are the ones that are commonly used,
mainly because [1] would have required modifications to calling conventions
that were well established when languages supporting exceptions were
introduced. A similar problem exists for closure pointers in legacy ABIs.

Note also that if the exception return PC is handled using technique [4],
then the Clu implementation naturally extends to non-local return (i.e. an
exception returning to a call stack that is several frames up). Once you
have a mechanism in place for "one step" return, the propagation of the
exception can be handled by code that is emitted into the "try" phase of
the try/catch block to store the chaining return information.


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

Reply via email to