2014-04-06 6 views
26

Ich glaube, ich beobachte den .NET JIT Compiler, der Aufrufe leerer statischer Methoden, die keine Nebeneffekte haben, nicht einreiht oder optimiert, was angesichts einiger maßgeschneiderter Online-Ressourcen ein wenig überraschend ist.Warum sollte der .NET JIT-Compiler entscheiden, Aufrufe von leeren statischen Methoden, die keine Nebenwirkungen haben, nicht zu inline zu verarbeiten oder zu optimieren?

Meine Umgebung ist Visual Studio 2013 auf x64, Windows 8.1, .NET Framework 4.5.

dieses einfache Testprogramm gegeben (https://ideone.com/2BRCpC)

class Program 
{ 
    static void EmptyBody() 
    { 
    } 

    static void Main() 
    { 
     EmptyBody(); 
    } 
} 

Ein Release-Build mit Optimierungen des obigen Programms erzeugt folgende MSIL für Main und EmptyBody:

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    // Code size  6 (0x6) 
    .maxstack 8 
    IL_0000: call  void Program::EmptyBody() 
    IL_0005: ret 
} // end of method Program::Main 

.method private hidebysig static void EmptyBody() cil managed 
{ 
    // Code size  1 (0x1) 
    .maxstack 8 
    IL_0000: ret 
} // end of method Program::EmptyBody 

Es ist nicht verwunderlich, dass die MSIL enthält einen Aufruf von Main an EmptyBody, da erwartet wird, dass der C# -Compiler solche Aufrufe nicht inline oder optimiert. Ich dachte jedoch, dass der JIT-Compiler dann diesen Aufruf inline oder optimieren würde. Aber das scheint nicht zu passieren.

Wenn ich das obige Programm und breche in den Debugger in Main ausführen, wird die erzeugte Baugruppe dies:

00572621 mov   ebp,esp 
00572623 cmp   dword ptr ds:[4320B84h],0 
0057262A je   00572631 
0057262C call  73E6AF20 
00572631 call  dword ptr ds:[4321578h] 

Der Befehlszeiger wird sofort bei 00.572.631 bis zur letzten Zeile gesetzt, die der Anruf an EmptyBody ist . Der Schritt in EmptyBody wird die generierte Assembly gefunden

00BD2651 mov   ebp,esp 
00BD2653 cmp   dword ptr ds:[4B00B84h],0 
00BD265A je   00BD2661 
00BD265C call  73E6AF20 
00BD2661 nop 
00BD2662 pop   ebp 
00BD2663 ret 

Der Befehlszeiger sein wird sofort an die nop Linie bei 00BD2661, die nichts tun, und ich kann nicht erraten, warum es in erster Linie erzeugt wird.

Da die beiden Assembly-Snippets den gleichen 4-Befehl-Header teilen, gehe ich davon aus, dass es sich nur um die normale Methodeneintrags-Kesseltafel handelt, auf der der Stack und so eingerichtet ist. Ich bin daran interessiert, zu lernen, zu wissen, was diese wiederkehrenden Anweisungen tun würde, aber:

00BD2653 cmp   dword ptr ds:[4B00B84h],0 
00BD265A je   00BD2661 
00BD265C call  73E6AF20 

Wie auch immer, die wichtigste Frage ist: Warum funktioniert der JIT-Compiler produzieren Assembly, die die leeren Körper statische Methode EmptyBody nennt?

+9

Ich bin kein Experte für C#. aber das Beobachten eines Systems ändert es;) Sie sehen den Code möglicherweise vollständig zugunsten Ihres Debuggers. –

+0

Wahr. Dann bin ich neugierig zu wissen, wie man überhaupt wissen kann, ob ein Anruf weg optimiert wurde oder nicht, was einige der "bespokten Online-Ressourcen" behauptet haben :-) –

+0

@JohannGerell Schalten Sie das Debug-Flag aus und kompilieren Sie für die Veröffentlichung Modus, dann fügen Sie einen Debugger zur Laufzeit, das wird sicherstellen, dass Sie den tatsächlichen Code debuggen. Ich glaube nicht, dass der JIT den Debugger überwachen wird, um zu sehen, ob er später angehängt wird, und basierend darauf Änderungen an der ASM vorzunehmen. – rolls

Antwort

31

Nachdem ich ein bisschen weiter gegraben habe, stellt sich heraus, dass ich diese Frage selbst beantworten kann. Wie unter http://blogs.msdn.com/b/vancem/archive/2006/02/20/535807.aspx erläutert, beeinflusst die Beobachtung der Disassemblierung eines optimierten Release-Builds unter dem Debugger standardmäßig den JIT-Compiler.

Entmarkieren diese

  • 'JIT-Optimierung auf Modullast Unterdrückt'
  • 'My-Code aktivieren Sie einfach'

unter VS> Tools> Debuggen> Allgemein wird die "echte" zeigen JIT-Kompilierergebnis, das für den Anruf zu EmptyBody in meinem Main oben ist:

004C2620 ret 

Das bedeutet, dass der Anruf an EmptyBody vollständig entfernt wird, was erwartet wurde und die Welt ist immer noch ein glücklicher und etwas vorhersehbarer Ort zum Leben :)

+2

Der 'nop' ist ein totes Werbegeschenk, dass dies geschieht. Wenn Sie diese sehen, wissen Sie, was zu tun ist :) –

+0

Der verlinkte Blog-Artikel sagt das gleiche: Es sollte keine 'nop' geben, wenn Sie den Rat richtig befolgt haben. –