欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表

.net本质论-方法(二)

创建时间:2012年12月10日 21:03  阅读次数:(4042)
分享到:
CLR通过方法的声明类型的方法表路由(route)所有的方法调用。例如,对于下面这个简单的类Bob,从Bob.f到Bob.c的调用总是通过该类的方法表。
Class Bob
{
static int x,
static void a(){x+=2;}
static void b(){x+=3;}
static void c(){x+=4}
static void f()
{c(); b(); a();}
}

实际上,对于Bob.f方法,对应的IA-32的本机代码是这样的;设立堆栈帧
push ebp
mov ebp,esp

;通过方法表调用Bob.c
call dword ptr ds:[137565Ch]

;通过力法表调用Bob.b
call dword ptr ds[375658h]

;通过方法表调用Bob.a
call dword ptr ds: [375654n]

;清理堆栈并返回
pop ebp
ret

在IA-32 call指令中使用的地址依次对应的方法表入口为:Bob.c,ob.b和3ob.a。

类型方法表的每个入口项指向一个惟一的存根例程( stub routine)。初始化时,每个存根例程包含一个对于CLR的JIT编译器的调用(它由内部的PerStubWorker程序公开)。在JIT编译器生成本机代码后,它会重写存根例程,插入一个jmp指令跳转到刚才JIT编译的代码,这意味着对于方法随之而来的调用,除了调用点和方法体之间的jmp指令,不会有别的开销,这个技术酷似Visual C++6.0新增加的延迟加载(delay-load)特征。在《Microsoft Systems Journal》1998年12月份期刊中由Mart Peitrek和JeffRichter撰写的两篇文章,对该特征进行了详尽的解释。

图6.1展示了正在被实时编译时的这个简单的C#类。尤其展示了 Bob.f的调用过程中的Bob方法表的快照,具体是在Bob.b调用Bob.c之后,且调用b或a之前这一瞬间的快照。注意,由于Bob.c方法已经被调用,c的存根只是一个jmp指令,它简单地将控制权传递给Bob.c的本机代码。相比之下,由于Bob.a和Bob.b将要被调用,a和b的存根例程将包含通用的call语句,它将控制权传递给JIT编译器。

图6.1并没有从技术上进行全面解释。尤其是当每个方法的存根进行初始化时,既包含call语句,又包含指定方法的CIL的地址。方法存根调用单一的jmp指令也可能产生性能问题。然而,扩展的jmp指令所提供的间接性,使得CLR能够很快地调整应用程序的工作集。如果CLR发现给定的方法不再需要,就会“抛弃”本机方法体,重新将jmp指令指向JIT例程。不妨设想下,本机方法体甚至可以在内存中被重新部署,以使得哪些被频繁方问的方法被放在同一个(或相邻的)虚拟内存页中。由于所有的了一小段序言(prolog)代码,从代码流中抽取方法的CIL的地址,然后,把地址传递蛤PreStubWorker(JIT编译器)。图6.2详细地展示了这个过程。



调用都是通过jmp指令,因此CLR只需要重写一个内存位置,就能够实现这种改变,而不管有多少调用点引用这个重定位的方法。n
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 83+80=? 的结果(结果是:163)
结  果: