2012-04-03 11 views
4

Ich las einen Beitrag auf Reddit auf Herb Stutter: JIT will never be as fast as native und jemand machte einen Kommentar, dass es unglaublich war, dass jemand Herb "falsch informiert", dass C# virtuelle Methoden anstelle von nicht virtuellen verwendet (Sie können den Artikel here lesen). Es brachte mich zum Nachdenken und ich machte ein kleines Programm und bemerkte, dass C# tatsächlich virtuelle Methoden für CIL (callvirt vs call) generiert. Aber dann wurde mir gesagt, dass es nicht so einfach ist und dass der JIT den Code einbinden kann, anstatt vtables und dynamischen Versand zu verwenden. Ich habe meinen Debugger hochgefahren und versucht zu sehen. Hier ist mein einfaches Programm:Wie man erkennt, ob ein Programm dynamischen Versand verwendet, indem man auf die Assembly schaut

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Test t = new Test(); 
      t.TestIt(); 
      t.TestOut(); 

     } 
    } 

    class Test 
    { 
     public Test() { } 
     public void TestIt() 
     { 
      Console.WriteLine("TESTIT"); 
     } 
     public void TestOut() 
     { 
      Console.WriteLine("TESTOUT"); 
     } 
    } 
} 

Und dann hier ist die Montage:

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Test t = new Test(); 
00000000 push  ebp 
00000001 mov   ebp,esp 
00000003 push  esi 
00000004 mov   ecx,439E68h 
00000009 call  FFCE0AD4 
0000000e mov   esi,eax 
      t.TestIt(); 
00000010 call  704BBEB8 // Call to Console.WriteLine() 
00000015 mov   ecx,eax 
00000017 mov   edx,dword ptr ds:[02A02088h] 
0000001d mov   eax,dword ptr [ecx] 
0000001f call  dword ptr [eax+000000D8h] 
      t.TestOut(); 
00000025 call  704BBEB8 // Call to Console.WriteLine() 
0000002a mov   ecx,eax 
0000002c mov   edx,dword ptr ds:[02A0208Ch] 
00000032 mov   eax,dword ptr [ecx] 
00000034 call  dword ptr [eax+000000D8h] 
0000003a pop   esi 

    } 
0000003b pop   ebp 
0000003c ret  

Meine Frage ist: durch in der Sammelstelle der Suche, wie man nicht sagen, ob es dynamische Dispatch verwendet? Meine Vermutung ist, dass es wegen dieser vier Befehle, die ähneln, was ich von meiner Programmiersprache Klasse erinnern:

0000002a mov   ecx,eax 
0000002c mov   edx,dword ptr ds:[02A0208Ch] 
00000032 mov   eax,dword ptr [ecx] 
00000034 call  dword ptr [eax+000000D8h] 

Bin ich richtig in der Annahme ist das dynamische Dispatch? Wenn ja, gibt es noch andere verräterische Zeichen? Wenn ich falsch liege, wie würde ich in der Lage sein zu sagen, ob es sich um dynamischen Versand handelt oder nicht?

Antwort

2

Ja, das Muster, das ein VTable artiges Ding schaut auf und verwendet dann die abgerufenen Adresse einen Funktionsaufruf

00000032 mov   eax,dword ptr [ecx] 
00000034 call  dword ptr [eax+000000D8h] 

Zeichen der dynamischen Dispatch sind auszuführen (auch dynamische Bindung genannt). Das Muster macht im Grunde Folgendes: Mit der Adresse des Objekts leitet es den Objekttyp ab (es findet nur den innerhalb des Objekts gespeicherten vtable-Zeiger) und findet heraus, welche Funktion aufgerufen werden soll (dessen Index in der vtable bekannt ist). Die Alternative, wenn Sie den tatsächlichen Typ des Objekts bereits kennen, besteht darin, einfach die richtige Funktion direkt aufzurufen.

Zum Beispiel in C++:

class Class { 
public: 
    virtual void Method() {} 
}; 

Class* object = new Object(); 
object->Method(); 
delete object; 

Hier ist der Compiler genügend Daten zu wissen, dass object speichert eine Adresse von Objekt vom Typ class Class, so dass es nur ein direktes (kein Vtable-Lookup) zu Class::Method() nennen emittieren kann, hat Das ist natürlich schneller.

+0

So ist das Muster der Suche nach einem Offset ein Zeichen der dynamischen Versand oder ist es die ganze 4 Befehlsgruppe, die das Tell Tale Zeichen ist? – Jetti

+0

@Jetti: Ich habe die Antwort bearbeitet. Das Vorzeichen des dynamischen Versands verwendet die Objektadresse, um die Funktionsadresse abzuleiten und dann diese Funktionsadresse zu verwenden, um den Aufruf auszuführen. – sharptooth

+0

vielen Dank. Ich war zu 80% sicher, dass es so war, aber aufgrund meiner mangelnden Erfahrung wollte ich nur sicher sein. – Jetti

3

Ein indirekter Anruf z.B. call dword ptr [eax+000000D8h] ist ein Zeichen der Verwendung einer virtuellen Tabelle

Verwandte Themen