如何通过查看程序集来判断程序是否使用动态调度 [英] How to tell if a program uses dynamic dispatch by looking at the assembly

查看:83
本文介绍了如何通过查看程序集来判断程序是否使用动态调度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Herb Stutter上的Reddit上阅读了一篇文章:像本机一样快,有人发表评论说,令人难以置信的是,有人叫Herb误传",C#使用虚拟方法而不是非虚拟方法(您可以阅读文章

然后是程序集:

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     

我的问题是这样的:通过查看程序集,如何分辨它是否在使用动态调度?我的直觉是因为这4条指令与我在编程语言课中所记得的相似:

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

我是否可以假设这是动态调度?如果是这样,还有其他迹象吗?如果我错了,我怎么能知道它是否是动态调度?

是的,这种模式将查找类似于vtable的内容,然后使用检索到的地址来执行函数调用

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

是动态调度(也称为动态绑定)的标志.该模式基本上执行以下操作:使用对象的地址来推导对象类型(实际上只是找到存储在对象内的vtable指针)并找到要调用的函数(在vtable中知道其索引).如果您已经知道对象的实际类型,则可以选择直接调用正确的函数.

例如在C ++中:

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

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

这里编译器有足够的数据来知道object存储的是类型为class Class的对象的地址,因此它可以发出对Class::Method()的直接调用(无vtable查找),这当然会更快. /p>

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?

解决方案

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.

这篇关于如何通过查看程序集来判断程序是否使用动态调度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆