问题
I read a post on Reddit on Herb Stutter: JIT will never be as fast as native and somebody made a comment that it was incredible somebody called Herb "misinformed" that C# uses virtual methods instead of non-virtual (you can read the article here). It got me to thinking and I made a quick little program and noticed that C# does in fact generate virtual methods for CIL (callvirt vs call). But then I was told it wasn't that easy and that the JIT may inline the code instead of using vtables and dynamic dispatch. I fired up my debugger and tried to see. Here is my simple program:
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");
}
}
}
And then here is the assembly:
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
My question is this: by looking at the assembly how does one tell if it is using dynamic dispatch? My hunch is that it is because of these 4 instructions which resemble what I remember from my programming language class:
0000002a mov ecx,eax
0000002c mov edx,dword ptr ds:[02A0208Ch]
00000032 mov eax,dword ptr [ecx]
00000034 call dword ptr [eax+000000D8h]
Am I correct in assuming this is dynamic dispatch? If so, are there any other tell-tale signs? If I'm wrong, how would I be able to tell if it is dynamic dispatch or not?
回答1:
Yes, this pattern which looks up a vtable-like thing and then uses the retrieved address to perform a function call
00000032 mov eax,dword ptr [ecx]
00000034 call dword ptr [eax+000000D8h]
is sign of dynamic dispatch (also called dynamic binding). The pattern basically does the following: using the address of the object it deduces the object type (it actually just finds the vtable pointer stored inside the object) and finds which function to call (knowing its index in the vtable). The alternative in case you already know the actual type of the object is to just call the right function directly.
For example in C++:
class Class {
public:
virtual void Method() {}
};
Class* object = new Object();
object->Method();
delete object;
Here the compiler has enough data to know that object
stores an address of object of type class Class
, so it can just emit a direct (no vtable lookup) call to Class::Method()
which is of course faster.
回答2:
An indirect call e.g. call dword ptr [eax+000000D8h]
is a sign of using a virtual table
来源:https://stackoverflow.com/questions/9995922/how-to-tell-if-a-program-uses-dynamic-dispatch-by-looking-at-the-assembly