300 likes | 628 Views
What Is An Exception?. An event within a computation that causes termination in a non-standard way. Examples:. Division by zero; Stack overflow; Null pointer. This Talk. Most modern languages support programming with exceptions, e.g. using throw and catch ;
E N D
What Is An Exception? An event within a computation that causes termination in a non-standard way. Examples: • Division by zero; • Stack overflow; • Null pointer.
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.
Step 1 - Arithmetic Expressions Syntax: data Expr = Val Int | Add Expr Expr Semantics: eval :: Expr Int eval (Val n) = n eval (Add x y) = eval x + eval y
Virtual machine: type Stack = [Int] data Op = PUSH Int | ADD type Code = [Op] Compiler: comp :: Expr Code comp (Val n) = [PUSH n] comp (Add x y) = comp x ++ comp y ++ [ADD]
eval Expr Int comp [] Code Stack exec [] Compiler Correctness Theorem: exec s (comp e) = eval e : s
Proof: by induction, using a distribution lemma: exec s (xs ++ ys) = exec (exec s xs) ys 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
Step 2 - Adding Exceptions Syntax: data Expr = ••• | Throw | Catch Expr Expr Semantics: eval :: Expr Maybe Int eval (Val n) = Just n eval (Throw) = Nothing eval (Add x y) = eval xeval y eval (Catch x h) = eval x eval h
Examples: eval Add (Val 1) (Val 2) Just 3 eval Add Throw (Val 2) Nothing eval Catch (Val 1) (Val 2) Just 1 eval Catch Throw (Val 2) Just 2
Virtual machine: data Op = ••• | THROW | MARK Code | UNMARK type Stack = [Item] data Item = VAL Int | HAN Code Compiler: comp (Throw) = [THROW] comp (Catch x h) = [MARK (comp h)] ++ comp x ++ [UNMARK]
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.
Implementation: unwind :: Stack Code Stack unwind [] ops = [] unwind (VAL n : s) ops = unwind s ops unwind (HAN h : s) ops = exec s (h ++ skip ops) skip :: Code Code skip [] = [] skip (UNMARK : ops) = ops skip (MARK h : ops) = skip (skip ops) skip (op : ops) = skip ops
Example 1 + (catch (2 + throw) 3) Code Stack
Example 1 + (catch (2 + throw) 3) Code Stack PUSH 1 MARK [PUSH 3] PUSH 2 THROW ADD UNMARK ADD
Example 1 + (catch (2 + throw) 3) Code Stack MARK [PUSH 3] PUSH 2 THROW ADD UNMARK ADD VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack PUSH 2 THROW ADD UNMARK ADD HAN [PUSH 3] VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack THROW ADD UNMARK ADD VAL 2 HAN [PUSH 3] VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack THROW ADD UNMARK ADD HAN [PUSH 3] VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack PUSH 3 THROW ADD UNMARK ADD VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack THROW ADD UNMARK ADD VAL 3 VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack ADD UNMARK ADD VAL 3 VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack UNMARK ADD VAL 3 VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack ADD VAL 3 VAL 1
Example 1 + (catch (2 + throw) 3) Code Stack VAL 4
Compiler Correctness eval Expr Maybe Int comp conv Code Stack exec [] where conv Nothing = [] conv (Just n) = [VAL n]
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) where trans :: Maybe Int Op trans Nothing = THROW trans (Just n) = PUSH n
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.
Step 3 - Adding Jumps Basic idea: Catch x h See the paper for further details. is now compiled to MARK a code for x UNMARK JUMP b a: code for h b: remaining code
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.
Further Work • Mechanical verification; • Calculating the compiler; • Modular compilers; • Generalising the language; • Compiler optimisations.