2013-03-19 3 views
4

Я написал очень простой класс в C#:Как понять JITed кода для «использования» с обработкой исключений в 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 

Я сбрасывал машинный код после JIT с WinDBG для него:

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 

Я мог бы понять код без исключения (комментарий выше), но, как код работает, когда было брошено исключение? Как код входит в код ниже комментария?

Update:

Некоторые люди думают, что мы должны начать с IL, поэтому я вставил код ниже:

.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 

Но я не думаю, что это помогает, так как IL почти все держит здесь, в C# как полный оператор try...finally. Я хочу понять, как здесь работает собственный код.

+0

Вы спрашиваете, как блок «Try ... finally» работает на уровне сборки? – keyboardP

+0

@GregC Мне просто интересно узнать больше о коде JITed. –

+0

@keyboardP Я думаю, что было бы полезно. –

ответ

6

Дрожание делает намного больше, чем то, что видно из окна разборки. Во-первых, он генерирует таблицу, которая описывает время жизни и хранение локальных переменных. Очень важно для сборщика мусора, ему нужна эта таблица для поиска ссылок на объекты.

И он создает таблицу для размотки для исключений. Который имеет очень желаемого имущества, он делает попробуйте заявление бесплатно. Существует нулевая стоимость при написании кода с обработкой исключений, для ввода блока try не требуется код. Таким образом, вы не видите ничего в разборке. Нет простого способа найти эту таблицу из отладчика. Довольно приличное описание из них is here.

+0

Утверждение 'try' дешево, но не совсем бесплатно - методы с таблицами обработки исключений не являются кандидатами для встраивания JIT. –

+0

+1 для хорошей ссылки – GregC

+0

Спасибо за ссылку. –

5

На самом деле вы смотрите на обработку исключений, поскольку в .NET не так много накладных расходов, когда не выбрасываются исключения. В случае исключения структура использует различные алгоритмы вне нормального пути потока кода (конкретные зависят от того, какой тип исключения был выброшен), который будет либо вызывать, либо явно указывать указатель на блок обработки исключений для метода ,