2013-03-22 22 views
6

Załóżmy, że mam następujący kod:W kodzie IL, dlaczego nie ma nop opcode w danej sytuacji? Dlaczego w danej sytuacji jest kod op.

public class Class1 
{ 
    private Class2 obj; 

    public void MethodA() 
    { 
     var class2 = new Class2(); 
     class2.PropertyI = 2; 
     obj = MethodB(class2); 
    } 

    public Class2 MethodB(Class2 class2) 
    { 
     return class2; 
    } 
} 

public class Class2 
{ 
    public int PropertyI { get; set; } 
} 

Wygenerowany kod IL od kompilacji z Visual Studio 2010 .NET 2.0 jako zespołu jest następujący:

.method public hidebysig instance void MethodA() cil managed 
{ 
    .maxstack 3 
    .locals init (
     [0] class ClassLibrary1.Class2 class2) 
    L_0000: nop 
    L_0001: newobj instance void ClassLibrary1.Class2::.ctor() 
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ldc.i4.2 
    L_0009: callvirt instance void ClassLibrary1.Class2::set_PropertyI(int32) 
    L_000e: nop 
    L_000f: ldarg.0 
    L_0010: ldarg.0 
    L_0011: ldloc.0 
    L_0012: call instance class ClassLibrary1.Class2 ClassLibrary1.Class1::MethodB(class ClassLibrary1.Class2) 
    L_0017: stfld class ClassLibrary1.Class2 ClassLibrary1.Class1::obj 
    L_001c: ret 
} 

.method public hidebysig instance class ClassLibrary1.Class2 MethodB(class ClassLibrary1.Class2 class2) cil managed 
{ 
    .maxstack 1 
    .locals init (
     [0] class ClassLibrary1.Class2 CS$1$0000) 
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: stloc.0 
    L_0003: br.s L_0005 
    L_0005: ldloc.0 
    L_0006: ret 
} 

moje pytania są następujące:

  1. W MethodA, dlaczego nie ma kodu między L_0006 a L_0007?
    • Od L_0001 do L_0006 różnią się od L_0007 do L_0009, dlaczego nie ma nop opcode?
  2. W MethodB, dlaczego jest L_0003 konieczne?
+1

Czy kompilujesz w wersji? Ponieważ słyszałem, że w nagłówkach metod, kompilacja debugowania ma kody NOP. –

+0

Kompiluję w debugowaniu. – cm007

Odpowiedz

9

Kompilator C# emituje instrukcję NOP na nawias klamrowy. Co sprawia, że ​​łatwiej jest ustawić punkty przerwania w kodzie. Debugger zezwala tylko na ustawienie punktu przerwania na kodzie, a nawias klamrowy zwykle nie tworzy żadnego kodu. Jest to po prostu prosta pomoc w debugowaniu, te NOP-y nie zostaną wygenerowane w wersji Release.

Instrukcja BR.S to drobna usterka kompilatora, nie ma ona peephole optimizer, aby pozbyć się tego rodzaju nieistotnych instrukcji. Ogólnie rzecz biorąc, nie jest zadaniem kompilatora C# optymalizacji kodu, który jest wykonywany przez the jitter. Które łatwo i łatwo usuniesz instrukcję.

+0

Jestem prawie pewien, że gałąź zostanie usunięta w trybie Release. Powszechne jest, że takie śmieci są produkowane przez wcześniejsze przepustki kompilatora, a ich usunięcie jest banalne. – usr

+0

Moje pytanie było bardziej zbliżone do tego, dlaczego w opcjach 'L_000e' istnieje' op-kod ', ale nie pomiędzy' L_0006' i 'L_0007'? Widzę, że kod 'nop' jest potrzebny w' L_0000' do ustawienia punktu przerwania na nawiasie klamrowym rozpoczynającym metodę, ale dlaczego w 'L_000e', a nie między' L_0006' a 'L_0007'? – cm007

+1

W L_0006 nie ma nawiasów klamrowych. L_000e jest niepotrzebny w taki sam sposób, w jaki BR.S było niepotrzebne. To naprawdę nie ma znaczenia, to nie musi być bezbłędne. Błędy są naprawiane, gdy trzeba je naprawić, nie dlatego, że istnieją. Pozbycie się fałszywego gen kodu z rekurencyjnego przyzwoitego parsera może być trudne i naprawianie nie zawsze jest warte ryzyka jego złamania. Jeśli chcesz zgubić przyczynę, możesz przestudiować kod źródłowy kompilatora C# z katalogu dystrybucyjnego SSCLI20, csharp/sccomp. –

1

Wszystko, co widzisz, ponieważ kompilujesz w trybie debugowania. Nadmiarowe skoki i nopy są wyłączone z optymalizacją, a także wsparciem debugowania (jak sądzę).

Skompiluj w trybie zwolnienia.

+0

Dzięki. Kompilowanie w trybie Release dało MethodB tylko dwie instrukcje 'ldarg.1'' ret'. – cm007

Powiązane problemy