我在 Herb Stutter 上阅读了 Reddit 上的一篇文章:JIT 永远不会像原生那样快,有人发表评论说令人难以置信的是,有人称 Herb “误导”了 C# 使用虚拟方法而不是非虚拟方法(你可以在这里阅读这篇文章)。这让我开始思考,我做了一个快速的小程序,并注意到 C# 实际上确实为 CIL 生成了虚拟方法(callvirt vs call)。但后来有人告诉我,这并不容易,而且 JIT 可能会内联代码而不是使用 vtables 和动态调度。我启动了调试器并试图查看。这是我的简单程序:
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");
}
}
}
然后这里是程序集:
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]
我假设这是动态调度是否正确?如果是这样,是否还有其他明显的迹象?如果我错了,我怎么知道它是否是动态调度?