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
