What Is An Exception?Division by zero;Stack overflow;Null pointer.Examples:An event within a computation that causes termination in a non-standard way.
This TalkMost modern languages support programming with exceptions, e.g. using throw and catch;
The compilation of such exception primitives is traditionally viewed as an advanced topic;
We give a simple explanation and verification, using elementary functional techniques.
Step 1 - Arithmetic Expressionsdata Expr = Val Int | Add Expr Expreval :: Expr Inteval (Val n) = neval (Add x y) = eval x + eval ySyntax:Semantics:
type Stack = [Int]
data Op = PUSH Int | ADD
type Code = [Op]comp :: Expr Codecomp (Val n) = [PUSH n]comp (Add x y) = comp x ++ comp y ++ [ADD]Virtual machine:Compiler:
Compiler Correctnessexec s (comp e) = eval e : sTheorem:
Proof: by induction, using a distribution lemma:However, we can avoid this lemma and shorten the proof by 60% by generalising the theorem: exec s (comp e ++ ops)= exec (eval e : s) ops exec s (xs ++ ys)= exec (exec s xs) ys
Step 2 - Adding Exceptionseval :: Expr Maybe Inteval (Val n) = Just neval (Throw) = Nothingeval (Add x y) = eval x eval yeval (Catch x h) = eval x eval hdata Expr = | Throw | Catch Expr ExprSyntax:Semantics:
Add (Val 1) (Val 2)Add Throw (Val 2)Catch (Val 1) (Val 2)Catch Throw (Val 2)Just 3NothingJust 1Just 2evalevalevalevalExamples:
data Op = | THROW | MARK Code | UNMARK
type Stack = [Item]
data Item = VAL Int | HAN Codecomp (Throw) = [THROW]comp (Catch x h) = [MARK (comp h)] ++ comp x ++ [UNMARK]Virtual machine:Compiler:
How Is THROW Executed?Informally, we must:Unwind the stack seeking a handler;
Execute the first handler found, if any;
Skip to the next part of the computation.
skip :: Code Codeskip  = skip (UNMARK : ops) = opsskip (MARK h : ops) = skip (skip ops)skip (op : ops) = skip opsunwind :: Stack Code Stackunwind  ops = unwind (VAL n : s) ops = unwind s opsunwind (HAN h : s) ops = exec s (h ++ skip ops)Implementation:
Example1 + (catch (2 + throw) 3)StackCode
Example1 + (catch (2 + throw) 3)PUSH 1MARK [PUSH 3]PUSH 2THROWADDUNMARKADDStackCode
Example1 + (catch (2 + throw) 3)MARK [PUSH 3]PUSH 2THROWADDUNMARKADDStackCodeVAL 1
Example1 + (catch (2 + throw) 3)PUSH 2THROWADDUNMARKADDStackCodeHAN [PUSH 3]VAL 1
Example1 + (catch (2 + throw) 3)THROWADDUNMARKADDStackCodeVAL 2HAN [PUSH 3]VAL 1
Example1 + (catch (2 + throw) 3)THROWADDUNMARKADDStackCodeHAN [PUSH 3]VAL 1
Example1 + (catch (2 + throw) 3)PUSH 3THROW ADD UNMARK ADD StackCodeVAL 1
Example1 + (catch (2 + throw) 3)THROW ADD UNMARK ADD StackCodeVAL 3VAL 1
Example1 + (catch (2 + throw) 3)ADD UNMARK ADD StackCodeVAL 3VAL 1
Example1 + (catch (2 + throw) 3)UNMARK ADD StackCodeVAL 3VAL 1
Example1 + (catch (2 + throw) 3)ADD StackCodeVAL 3VAL 1
Example1 + (catch (2 + throw) 3)StackCodeVAL 4
Compiler CorrectnessExprMaybe IntCodeStackevalexec compconvconv Nothing = conv (Just n) = [VAL n]where
As previously, we generalise to an arbitrary initial stack and arbitrary additional code.
Theorem: exec s (comp e ++ ops)= exec s (trans (eval e) : ops)trans :: Maybe Int Optrans Nothing = THROWtrans (Just n) = PUSH nwhere
Proof: by induction, using a skipping lemma:skip (comp e ++ ops) = skip opsNotes:The proof is 3.5 pages of simple calculation;
The quickcheck tool was very useful as an aid to simplifying the definitions and results.
Step 3 - Adding Jumps MARK a code for x UNMARK JUMP ba: code for hb: remaining codeCatch x his now compiled toBasic idea:See the paper for further details.
SummaryExplanation and verification of the compilation of exceptions using stack unwinding.
Stepwise development to aid understanding:1 - Arithmetic expressions;
2 - Adding exceptions;
3 - Adding jumps.
Further WorkMechanical verification;Modular compilers;Calculating the compiler;Generalising the language;Compiler optimisations.