Merge pull request #5668 from kumpera/wasm-work-p4
[mono.git] / docs / exceptions
index ab0f2dec94ad67ae47efeea238dd671a02b28553..bd22de9f25f4ad5886baa969e9465e6f914fc11e 100644 (file)
@@ -1,3 +1,7 @@
+            Exception Implementation in the Mono Runtime
+                Dietmar Maurer (dietmar@ximian.com)
+                       (C) 2001 Ximian, Inc.
+
 Exception implementation (jit):
 ===============================
 
@@ -8,8 +12,15 @@ We record the code address (start_address, size) of all methods. That way it is
 possible to map an instruction pointer (IP) to the method information needed
 for unwinding the stack:
 
+We also save a Last Managed Frame (LMF) structure at each call from managed to
+unmanaged code. That way we can recover from exceptions inside unmanaged code.
+
 void handle_exception ((struct sigcontext *ctx, gpointer obj)
 {
+        if (ctx->bp < mono_end_of_stack) {
+               /* unhandled exception */
+               abort ();
+       }
 
        info = mono_jit_info_table_find (mono_jit_info_table, ctx->ip);
 
@@ -21,14 +32,20 @@ void handle_exception ((struct sigcontext *ctx, gpointer obj)
                execute_all_finally_handler ();
 
                // restore register, including IP and Frame pointer
-               restore_caller_saved_registers (ji, ctx);
+               ctx = restore_caller_saved_registers_from_ctx (ji, ctx);
 
                // continue unwinding
                handle_exception (ctx, obj);
 
        } else {
 
-               // not implemented 
+               lmf = get_last_managed_frame ();
+               
+               // restore register, including IP and Frame pointer
+               ctx = restore_caller_saved_registers_from_lmf (ji, lmf);
+               
+               // continue unwinding
+               handle_exception (ctx, obj);
        }
 }
 
@@ -40,15 +57,17 @@ leave: is simply translated into a branch to the target. If the leave
 instruction is inside a finally block (but not inside another handler)
 we call the finally handler before we branch to the target.
 
-finally/endfinally: is translated into subroutine ending with a "return"
-statement. The subroutine does not save EBP/ESP, because we need access to the
-local variables of the enclosing method. We have to use a "call"
-instruction to execute such finally handlers. This makes it possible to
-execute them inside the stack unwinding code.
+finally/endfinally, filter/endfilter: is translated into subroutine ending with
+a "return" statement. The subroutine does not save EBP, because we need access
+to the local variables of the enclosing method. Its is possible that
+instructions inside those handlers modify the stack pointer, thus we save the
+stack pointer at the start of the handler, and restore it at the end. We have
+to use a "call" instruction to execute such finally handlers. This makes it
+also possible to execute them inside the stack unwinding code. The exception
+object for filters is passed in a local variable (cfg->exvar).
 
-throw: we first save all regs into a sigcontext struct (we pass the
-exception object in register ECX), and then call the stack unwinding
-code.
+throw: we first save all regs into a sigcontext struct and then call the stack
+unwinding code.
 
-catch handler: receives the exception object in ECX. They store that
-object into a local variable, so that rethrow can access the object.
+catch handler: catch hanlders are always called from the stack unwinding
+code. The exception object is passed in a local variable (cfg->exvar).