ab0f2dec94ad67ae47efeea238dd671a02b28553
[mono.git] / docs / exceptions
1 Exception implementation (jit):
2 ===============================
3
4 Stack unwinding:
5 ================
6
7 We record the code address (start_address, size) of all methods. That way it is
8 possible to map an instruction pointer (IP) to the method information needed
9 for unwinding the stack:
10
11 void handle_exception ((struct sigcontext *ctx, gpointer obj)
12 {
13
14         info = mono_jit_info_table_find (mono_jit_info_table, ctx->ip);
15
16         if (info) { // we are inside managed code
17
18                 if (ch =  find_catch_handler ())
19                         execute_catch_handler (ch, ctx, obj); 
20                 
21                 execute_all_finally_handler ();
22
23                 // restore register, including IP and Frame pointer
24                 restore_caller_saved_registers (ji, ctx);
25
26                 // continue unwinding
27                 handle_exception (ctx, obj);
28
29         } else {
30
31                 // not implemented 
32         }
33 }
34
35
36 Code generation:
37 ================
38
39 leave: is simply translated into a branch to the target. If the leave
40 instruction is inside a finally block (but not inside another handler)
41 we call the finally handler before we branch to the target.
42
43 finally/endfinally: is translated into subroutine ending with a "return"
44 statement. The subroutine does not save EBP/ESP, because we need access to the
45 local variables of the enclosing method. We have to use a "call"
46 instruction to execute such finally handlers. This makes it possible to
47 execute them inside the stack unwinding code.
48
49 throw: we first save all regs into a sigcontext struct (we pass the
50 exception object in register ECX), and then call the stack unwinding
51 code.
52
53 catch handler: receives the exception object in ECX. They store that
54 object into a local variable, so that rethrow can access the object.