2
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.
3
This Talk
Most 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.
4
Step 1 - Arithmetic Expressions
data Expr = Val Int | Add Expr Expr
eval :: Expr Inteval (Val n) = neval (Add x y) = eval x + eval y
Syntax:
Semantics:
5
type Stack = [Int]
data Op = PUSH Int | ADD
type Code = [Op]
comp :: Expr Code
comp (Val n) = [PUSH n]
comp (Add x y) = comp x ++ comp y ++ [ADD]
Virtual machine:
Compiler:
6
Compiler Correctness
Expr Int
Code Stack
eval
exec []
comp []
exec s (comp e) = eval e : s
Theorem:
7
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
8
eval :: Expr Maybe Inteval (Val n) = Just neval (Throw) = Nothingeval (Add x y) = eval x eval yeval (Catch x h) = eval x eval h
Step 2 - Adding Exceptions
data Expr = ••• | Throw | Catch Expr Expr
Syntax:
Semantics:
9
Add (Val 1) (Val 2)
Add Throw (Val 2)
Catch (Val 1) (Val 2)
Catch Throw (Val 2)
Just 3
Nothing
Just 1
Just 2
eval
eval
eval
eval
Examples:
10
data Op = ••• | THROW | MARK Code | UNMARK
type Stack = [Item]
data Item = VAL Int | HAN Code
comp (Throw) = [THROW]
comp (Catch x h) =
[MARK (comp h)] ++ comp x ++ [UNMARK]
Virtual machine:
Compiler:
11
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.
12
skip :: Code Codeskip [] = []skip (UNMARK : ops) = opsskip (MARK h : ops) = skip (skip ops)skip (op : ops) = skip ops
unwind :: Stack Code Stackunwind [] ops = []unwind (VAL n : s) ops = unwind s opsunwind (HAN h : s) ops = exec s (h ++ skip ops)
Implementation:
25
Compiler Correctness
Expr Maybe Int
Code Stack
eval
exec []
comp conv
conv Nothing = []conv (Just n) = [VAL n]
where
26
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 n
where
27
Proof: by induction, using a skipping lemma:
skip (comp e ++ ops) = skip ops
Notes:
The proof is 3.5 pages of simple calculation;
The quickcheck tool was very useful as an aid to simplifying the definitions and results.
28
Step 3 - Adding Jumps
MARK a code for x UNMARK JUMP ba: code for hb: remaining code
Catch x h
is now compiled to
Basic idea:
See the paper for further
details.
29
Summary
Explanation and verification of the compilation of exceptions using stack unwinding.
Stepwise development to aid understanding:
1 - Arithmetic expressions;
2 - Adding exceptions;
3 - Adding jumps.