I've written a very simple class in C#:
class DisposableClass : IDisposable {
public void Dispose() { }
}
static void UsingClass() { // line 31
using (var dc = new DisposableClass()) { // line 32
DoSomething(dc); // line 33
} // line 34
} // line 35
I've dumped the native code after JIT with WinDBG for it:
0:000> !u 000007fe87d30120
Normal JIT generated code
SimpleConsole.Program.UsingClass()
Begin 000007fe87d30120, size 80
c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 32:
>>> 000007fe`87d30120 55 push rbp
000007fe`87d30121 4883ec30 sub rsp,30h
000007fe`87d30125 488d6c2420 lea rbp,[rsp+20h]
000007fe`87d3012a 48896500 mov qword ptr [rbp],rsp
000007fe`87d3012e 48c7450800000000 mov qword ptr [rbp+8],0
000007fe`87d30136 488d0d6b47eeff lea rcx,[000007fe`87c148a8]
000007fe`87d3013d e8fe24665f call clr+0x2640 (000007fe`e7392640) (JitHelp: CORINFO_HELP_NEWSFAST) // new DisposableClass()
000007fe`87d30142 48894508 mov qword ptr [rbp+8],rax
c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 33:
000007fe`87d30146 488b4d08 mov rcx,qword ptr [rbp+8]
000007fe`87d3014a e8d1beeeff call 000007fe`87c1c020 (SimpleConsole.Program.DoSomething(System.Object), mdToken: 0000000006000012)
000007fe`87d3014f 90 nop
000007fe`87d30150 90 nop
c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 35:
000007fe`87d30151 488b4d08 mov rcx,qword ptr [rbp+8]
000007fe`87d30155 4c8d1dc4feeeff lea r11,[000007fe`87c20020]
000007fe`87d3015c ff15befeeeff call qword ptr [000007fe`87c20020] // Call Dispose()
000007fe`87d30162 90 nop
000007fe`87d30163 488d6510 lea rsp,[rbp+10h]
000007fe`87d30167 5d pop rbp
000007fe`87d30168 c3 ret
// I could understand the code above (without exception thrown).
c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 32:
000007fe`87d30169 55 push rbp
000007fe`87d3016a 4883ec30 sub rsp,30h
000007fe`87d3016e 488b6920 mov rbp,qword ptr [rcx+20h]
000007fe`87d30172 48896c2420 mov qword ptr [rsp+20h],rbp
000007fe`87d30177 488d6d20 lea rbp,[rbp+20h]
c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 35:
000007fe`87d3017b 48837d0800 cmp qword ptr [rbp+8],0
000007fe`87d30180 7417 je 000007fe`87d30199
000007fe`87d30182 488d1597feeeff lea rdx,[000007fe`87c20020]
000007fe`87d30189 488b4508 mov rax,qword ptr [rbp+8]
000007fe`87d3018d 803800 cmp byte ptr [rax],0
000007fe`87d30190 488b4d08 mov rcx,qword ptr [rbp+8]
000007fe`87d30194 4c8bda mov r11,rdx
000007fe`87d30197 ff12 call qword ptr [rdx]
000007fe`87d30199 90 nop
000007fe`87d3019a 4883c430 add rsp,30h
000007fe`87d3019e 5d pop rbp
000007fe`87d3019f c3 ret
I could understand the code without exception (commented above), but how the code works when an exception was thrown? How the code goes into the code below the comment?
Update:
Some people think we should start from IL so I pasted the code below:
.method private hidebysig static
void UsingClass () cil managed noinlining
{
// Method begins at RVA 0x23bc
// Code size 25 (0x19)
.maxstack 1
.locals init (
[0] class SimpleConsole.DisposableClass dc
)
IL_0000: newobj instance void SimpleConsole.DisposableClass::.ctor()
IL_0005: stloc.0
.try
{
IL_0006: ldloc.0
IL_0007: call void SimpleConsole.Program::DoSomething(object)
IL_000c: leave.s IL_0018
} // end .try
finally
{
IL_000e: ldloc.0
IL_000f: brfalse.s IL_0017
IL_0011: ldloc.0
IL_0012: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0017: endfinally
} // end handler
IL_0018: ret
} // end of method Program::UsingClass
But I don't think it helps since IL almost keeps everything here in C# like the complete try...finally
statement. What I want to understand is how the native code handles exception here.
The jitter does a lot more than what's ever visible from the Disassembly window. For one, it generates a table that describes the lifetime and storage of local variables. Very important for the garbage collector, it needs that table to find object references.
And it generates an unwind table for exceptions. Which has a very desirable property, it makes a try statement free. There is zero cost in writing code that has exception handling, no code is required to enter a try block. So you don't see any in the dissassembly. There is no easy way to locate that table from the debugger. A pretty decent description of them is here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With