1 Author: Dietmar Maurer (dietmar@ximian.com)
4 Exception implementation (jit):
5 ===============================
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:
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.
17 void handle_exception ((struct sigcontext *ctx, gpointer obj)
19 if (ctx->bp < mono_end_of_stack) {
20 /* unhandled exception */
24 info = mono_jit_info_table_find (mono_jit_info_table, ctx->ip);
26 if (info) { // we are inside managed code
28 if (ch = find_catch_handler ())
29 execute_catch_handler (ch, ctx, obj);
31 execute_all_finally_handler ();
33 // restore register, including IP and Frame pointer
34 ctx = restore_caller_saved_registers_from_ctx (ji, ctx);
37 handle_exception (ctx, obj);
41 lmf = get_last_managed_frame ();
43 // restore register, including IP and Frame pointer
44 ctx = restore_caller_saved_registers_from_lmf (ji, lmf);
47 handle_exception (ctx, obj);
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.
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.
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
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.