分享
 
 
 

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

王朝c#·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

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该内部数据结构中对应的内存地址,该地址中的内容是对应的存根例程的开始地址。

c()的汇编显示为:

push ebp

mov ebp,esp

add dword ptr ds:[0097539Ch],4

nop

pop ebp

ret

[注]0097539c是Bob.x的内存地址。

b()的汇编显示为:

push ebp

mov ebp,esp

add dword ptr ds:[0097539Ch],3

nop

pop ebp

ret

[注]0097539c是Bob.x的内存地址。

a()的汇编显示为:

push ebp

mov ebp,esp

add dword ptr ds:[0097539Ch],2

nop

pop ebp

ret

[注]0097539c是Bob.x的内存地址。

下面,让我们看看调试时,地址为00975394h、00975390h、0097538ch、00975388h中的内容:

0x00975384 2b 85 bf 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 00 00 00 00 00 00 00 00

绿色的是Bob.f()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

紫色的是Bob.c()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

灰色的是Bob.b()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

黄色的是Bob.a()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

[注]红色的内容则是Bob.x的值哦!不信吗?那你看看下面的调试过程中红色处的值的变化,就明白了:

进入f()前为:

0x00975384 2b 85 bf 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 00 00 00 00 00 00 00 00

c()加4后变为:

0x00975384 2b 85 bf 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 04 00 00 00 00 00 00 00

加3后变为:

0x00975384 2b 85 bf 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 07 00 00 00 00 00 00 00

加2后变为:

0x00975384 2b 85 bf 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 09 00 00 00 00 00 00 00

下面让我们看看在调用Bob.f()之前存根例程处的内容:

0x00975303 e8 d0 52 7d ff 04 00 10 00 50 20 00 c0 02 00 fe

0x00975313 e8 c0 52 7d ff 05 00 10 00 6c 20 00 c0 03 00 fc

0x00975323 e8 b0 52 7d ff 06 00 10 00 88 20 00 c0 04 00 fa

0x00975333 e8 a0 52 7d ff 07 00 10 00 a4 20 00 c0 05 00 f8

绿色处是Bob.f()的存根例程的内容;

紫色处是Bob.c()的存根例程的内容;

灰色处是Bob.b()的存根例程的内容;

黄色处是Bob.a()的存根例程的内容;

下面让我们看看在进入Bob.f()方法体之后存根例程处的内容:

0x00975303 e8 d0 52 7d ff 04 00 10 00 50 20 00 c0 02 00 fe

0x00975313 e8 c0 52 7d ff 05 00 10 00 6c 20 00 c0 03 00 fc

0x00975323 e8 b0 52 7d ff 06 00 10 00 88 20 00 c0 04 00 fa

0x00975333 e9 40 ad 39 06 07 00 10 00 78 00 d1 06 05 00 f8

易见,只有Bob.f()的存根例程的内容起了变化。这说明,JIT编译器被调用了。同时,编译器将f()的CIL方法体转换为地址空间中的机器码版本。再替换了存根例程的原内容。替换后,f()方法的机器码版本的首地址是0x06d10078(蓝色标注处的内容)。你不信吗?那好,我们看一下0x06d10078处的内存内容:

0x06D10078 55 8b ec ff 15 90 53 97 00 ff 15 8c 53 97 00 ff

0x06D10088 15 88 53 97 00 90 5d c3 00 00 00 00 00 00 00 00

你不妨再回头看看f()的汇编显示,这里:

紫色处不正是对Bob.c()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

灰色处不正是对Bob.b()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

黄色处不正是对Bob.a()在CORINFO_CLASS_STRUCT该内部数据结构中对应的内存地址;

不正好对应了f()汇编显示中:

//调用Bob.c()方法

call dword ptr ds:[00975390h]

//调用Bob.b()方法

call dword ptr ds:[0097538Ch]

//调用Bob.a()方法

call dword ptr ds:[00975388h]

明白了吧!好了,下面对于c() 、b()、a()的调用也是一样的道理。对于接下来的调试会有如下的内存显示:

接下来的存根例程的内容:

进入c()后变为:

0x00975303 e8 d0 52 7d ff 04 00 10 00 50 20 00 c0 02 00 fe

0x00975313 e8 c0 52 7d ff 05 00 10 00 6c 20 00 c0 03 00 fc

0x00975323 e9 78 ad 39 06 06 00 10 00 a0 00 d1 06 04 00 fa

0x00975333 e9 40 ad 39 06 07 00 10 00 78 00 d1 06 05 00 f8

进入b()后变为:

0x00975303 e8 d0 52 7d ff 04 00 10 00 50 20 00 c0 02 00 fe

0x00975313 e9 a8 ad 39 06 05 00 10 00 c0 00 d1 06 03 00 fc

0x00975323 e9 78 ad 39 06 06 00 10 00 a0 00 d1 06 04 00 fa

0x00975333 e9 40 ad 39 06 07 00 10 00 78 00 d1 06 05 00 f8

进入a()后变为:

0x00975303 e9 d8 ad 39 06 04 00 10 00 e0 00 d1 06 02 00 fe

0x00975313 e9 a8 ad 39 06 05 00 10 00 c0 00 d1 06 03 00 fc

0x00975323 e9 78 ad 39 06 06 00 10 00 a0 00 d1 06 04 00 fa

0x00975333 e9 40 ad 39 06 07 00 10 00 78 00 d1 06 05 00 f8

进入c()后地址为0x06d100a0的内容(Bob.c()的机器码版本)如下:

0x06D100A0 55 8b ec 83 05 9c 53 97 00 04 90 5d c3 00 00 00

进入b()后地址为0x06d100c0的内容(Bob.b()的机器码版本)如下:

0x06D100C0 55 8b ec 83 05 9c 53 97 00 03 90 5d c3 00 00 00

进入a()后地址为0x06d100e0的内容(Bob.a()的机器码版本)如下:

0x06D100E0 55 8b ec 83 05 9c 53 97 00 02 90 5d c3 00 00 00

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有