How to tell if a program uses dynamic dispatch by

2019-06-28 07:06发布

问题:

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