Welcome to mirror list, hosted at ThFree Co, Russian Federation.

exceptions « docs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 05f1be03bbaee7d31e0183410fd5d3d79e151d1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Author: Dietmar Maurer (dietmar@ximian.com)
(C) 2001 Ximian, Inc.

Exception implementation (jit):
===============================

Stack unwinding:
================

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);

	if (info) { // we are inside managed code

		if (ch =  find_catch_handler ())
			execute_catch_handler (ch, ctx, obj); 
		
		execute_all_finally_handler ();

		// restore register, including IP and Frame pointer
		ctx = restore_caller_saved_registers_from_ctx (ji, ctx);

		// continue unwinding
		handle_exception (ctx, obj);

	} else {

	        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);
	}
}


Code generation:
================

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.

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.

catch handler: receives the exception object in ECX. They store that
object into a local variable, so that rethrow can access the object.