深入理解.NET 的JIT编译方式

作者:袖梨 2022-07-02
CLR只执行本机的机器代码。有两种方式产生本机的机器代码:实时编译(JIT)和预编译方式(产生native image)。下面,我想谈谈JIT。
CLR使用类型的方法表来路由所有的方法调用。类型的方法表由多个入口项组成。每个入口项指向一个唯一的存根例程(stub routine)。初始化时,每个存根例程包含一个对于CLR的JIT编译器的调用(它由内部的PreStubWorker程序公开)。在JIT编译器生成本机代码后,它会重写存根例程,插入一个jmp指令跳转到刚才JIT编译器的代码。只有当要调用某个方法时,JIT编译器才会将CIL的方法体编译为相应的本机机器码版本。这样可以优化程序的工作集。
对于如下的例子:
//using System;
public class Bob{
static int x;
static void a(){x+=2;}
static void b(){x+=3;}
static void c(){x+=4;}
public static void f()
{
c();
b();
a();
}
}
public class MyClass
{
public static void Main()
{

Bob.f();
}
}
用调试器进行JIT调试。
首先,看一下每个方法的汇编显示:
Main()的汇编显示为:
push ebp
mov ebp,esp
//调用Bob.f()方法
call dword ptr ds:[00975394h]
nop
pop ebp
ret
[注]00975394h是Bob.f()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址,该地址中的内容是对应的存根例程的开始地址。
f()的汇编显示为:
push ebp
mov ebp,esp
//调用Bob.c()方法
call dword ptr ds:[00975390h]
//调用Bob.b()方法
call dword ptr ds:[0097538Ch]
//调用Bob.a()方法
call dword ptr ds:[00975388h]
nop
pop ebp
ret
[注]00975390、0097538c、00975388分别为Bob.c()、Bob.b()、Bob.a()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址,该地址中的内容是对应的存根例程的开始地址。

相关文章

精彩推荐