2002-04-30 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / docs / exceptions
1 Author: Dietmar Maurer (dietmar@ximian.com)
2 (C) 2001 Ximian, Inc.
3
4 Exception implementation (jit):
5 ===============================
6
7 Stack unwinding:
8 ================
9
10 We record the code address (start_address, size) of all methods. That way it is
11 possible to map an instruction pointer (IP) to the method information needed
12 for unwinding the stack:
13
14 We also save a Last Managed Frame (LMF) structure at each call from managed to
15 unmanaged code. That way we can recover from exceptions inside unmanaged code.
16
17 void handle_exception ((struct sigcontext *ctx, gpointer obj)
18 {
19         if (ctx->bp < mono_end_of_stack) {
20                 /* unhandled exception */
21                 abort ();
22         }
23
24         info = mono_jit_info_table_find (mono_jit_info_table, ctx->ip);
25
26         if (info) { // we are inside managed code
27
28                 if (ch =  find_catch_handler ())
29                         execute_catch_handler (ch, ctx, obj); 
30                 
31                 execute_all_finally_handler ();
32
33                 // restore register, including IP and Frame pointer
34                 ctx = restore_caller_saved_registers_from_ctx (ji, ctx);
35
36                 // continue unwinding
37                 handle_exception (ctx, obj);
38
39         } else {
40
41                 lmf = get_last_managed_frame ();
42                 
43                 // restore register, including IP and Frame pointer
44                 ctx = restore_caller_saved_registers_from_lmf (ji, lmf);
45                 
46                 // continue unwinding
47                 handle_exception (ctx, obj);
48         }
49 }
50
51
52 Code generation:
53 ================
54
55 leave: is simply translated into a branch to the target. If the leave
56 instruction is inside a finally block (but not inside another handler)
57 we call the finally handler before we branch to the target.
58
59 finally/endfinally: is translated into subroutine ending with a "return"
60 statement. The subroutine does not save EBP/ESP, because we need access to the
61 local variables of the enclosing method. We have to use a "call"
62 instruction to execute such finally handlers. This makes it possible to
63 execute them inside the stack unwinding code.
64
65 throw: we first save all regs into a sigcontext struct (we pass the
66 exception object in register ECX), and then call the stack unwinding
67 code.
68
69 catch handler: receives the exception object in ECX. They store that
70 object into a local variable, so that rethrow can access the object.