exceptions 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. Author: Dietmar Maurer ([email protected])
  2. (C) 2001 Ximian, Inc.
  3. Exception implementation (jit):
  4. ===============================
  5. Stack unwinding:
  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. We also save a Last Managed Frame (LMF) structure at each call from managed to
  11. unmanaged code. That way we can recover from exceptions inside unmanaged code.
  12. void handle_exception ((struct sigcontext *ctx, gpointer obj)
  13. {
  14. if (ctx->bp < mono_end_of_stack) {
  15. /* unhandled exception */
  16. abort ();
  17. }
  18. info = mono_jit_info_table_find (mono_jit_info_table, ctx->ip);
  19. if (info) { // we are inside managed code
  20. if (ch = find_catch_handler ())
  21. execute_catch_handler (ch, ctx, obj);
  22. execute_all_finally_handler ();
  23. // restore register, including IP and Frame pointer
  24. ctx = restore_caller_saved_registers_from_ctx (ji, ctx);
  25. // continue unwinding
  26. handle_exception (ctx, obj);
  27. } else {
  28. lmf = get_last_managed_frame ();
  29. // restore register, including IP and Frame pointer
  30. ctx = restore_caller_saved_registers_from_lmf (ji, lmf);
  31. // continue unwinding
  32. handle_exception (ctx, obj);
  33. }
  34. }
  35. Code generation:
  36. ================
  37. leave: is simply translated into a branch to the target. If the leave
  38. instruction is inside a finally block (but not inside another handler)
  39. we call the finally handler before we branch to the target.
  40. finally/endfinally: is translated into subroutine ending with a "return"
  41. statement. The subroutine does not save EBP/ESP, because we need access to the
  42. local variables of the enclosing method. We have to use a "call"
  43. instruction to execute such finally handlers. This makes it possible to
  44. execute them inside the stack unwinding code.
  45. throw: we first save all regs into a sigcontext struct (we pass the
  46. exception object in register ECX), and then call the stack unwinding
  47. code.
  48. catch handler: receives the exception object in ECX. They store that
  49. object into a local variable, so that rethrow can access the object.