COMPILING EXCEPTIONS CORRECTLY Graham Hutton and Joel Wright University of Nottingham 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. 1 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. 2 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 3 Virtual machine: type Stack = [Int] data Op = PUSH Int | ADD type Code = [Op] Compiler: comp comp (Val n) :: Expr Code = [PUSH n] comp (Add x y) = comp x ++ comp y ++ [ADD] 4 Compiler Correctness Expr eval comp Code Int [] exec [] Stack Theorem: exec s (comp e) = eval e : s 5 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 6 Step 2 - Adding Exceptions Syntax: data Expr = ••• | Throw | Catch Expr Expr Semantics: eval eval eval eval eval :: (Val n) = (Throw) = (Add x y) = (Catch x h) = Expr Maybe Int Just n Nothing eval x eval y eval x eval h 7 Examples: Add (Val 1) (Val 2) Add Throw (Val 2) Catch (Val 1) (Val 2) Catch Throw (Val 2) eval eval eval eval Just 3 Nothing Just 1 Just 2 8 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] 9 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. 10 Implementation: unwind :: unwind [] ops = unwind (VAL n : s) ops = unwind (HAN h : s) ops = Stack Code Stack [] unwind s ops exec s (h ++ skip ops) skip skip skip skip skip Code Code [] ops skip (skip ops) skip ops [] (UNMARK : ops) (MARK h : ops) (op : ops) :: = = = = 11 Example 1 + (catch (2 + throw) 3) Code Stack 12 Example 1 + (catch (2 + throw) 3) Code Stack PUSH 1 MARK [PUSH 3] PUSH 2 THROW ADD UNMARK ADD 13 Example 1 + (catch (2 + throw) 3) Code MARK [PUSH 3] PUSH 2 THROW ADD UNMARK ADD Stack VAL 1 14 Example 1 + (catch (2 + throw) 3) Code PUSH 2 THROW ADD UNMARK ADD Stack HAN [PUSH 3] VAL 1 15 Example 1 + (catch (2 + throw) 3) Code THROW ADD UNMARK ADD Stack VAL 2 HAN [PUSH 3] VAL 1 16 Example 1 + (catch (2 + throw) 3) Code THROW ADD UNMARK ADD Stack HAN [PUSH 3] VAL 1 17 Example 1 + (catch (2 + throw) 3) Code PUSH 3 THROW ADD UNMARK ADD Stack VAL 1 18 Example 1 + (catch (2 + throw) 3) Code THROW ADD UNMARK ADD Stack VAL 3 VAL 1 19 Example 1 + (catch (2 + throw) 3) Code ADD UNMARK ADD Stack VAL 3 VAL 1 20 Example 1 + (catch (2 + throw) 3) Code UNMARK ADD Stack VAL 3 VAL 1 21 Example 1 + (catch (2 + throw) 3) Code ADD Stack VAL 3 VAL 1 22 Example 1 + (catch (2 + throw) 3) Code Stack VAL 4 23 Compiler Correctness Expr eval comp Code Maybe Int conv exec [] Stack where conv Nothing = [] conv (Just n) = [VAL n] 24 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 25 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. 26 Step 3 - Adding Jumps Basic idea: Catch x h is now compiled to See the paper for further details. MARK a code for x UNMARK JUMP b a: code for h b: remaining code 27 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. 28 Further Work Mechanical verification; Modular compilers; Calculating the compiler; Generalising the language; Compiler optimisations. 29
© Copyright 2026 Paperzz