exceptions 1.6 KB

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