.NET VM如何检查整数溢出?

时间:2010-01-12 01:01:28

标签: .net jit

众所周知并且爱.NET每次整数溢出时都会抛出IntegerOverflow异常。我认为这是一件非常好的事情。

但我不知道他们是如何做到这一点的。 x86不会捕获整数溢出,如果其他架构允许人们这样做,我会感到惊讶。我在x86中找到的最佳解决方案是在每次算术运算后都输入“INTO”指令。但我认为这会导致明显放缓。

他们可以在编译器中进行一些静态检查,以避免在可以证明操作不能溢出的情况下。但是当编译器无法确定操作的结果时,性能关键的内部循环呢?

我试着查看Mono来源,但我找不到他们进行这些检查的地方。

那么有谁知道他们真正做了什么?我真的很想知道。

旁注:有没有办法看到.NET JITC发出的x86代码?

2 个答案:

答案 0 :(得分:3)

开始调试,右键单击source,Go To Disassembly。你会看到这样的事情:

      int ix = int.MaxValue;
0000003a  mov         dword ptr [ebp-40h],7FFFFFFFh 
      int jx = 1;
00000041  mov         dword ptr [ebp-44h],1 
      Console.WriteLine(ix + jx);
00000048  mov         ecx,dword ptr [ebp-40h] 
0000004b  add         ecx,dword ptr [ebp-44h] 
0000004e  jno         00000055                 <--- overflow test
00000050  call        6D7ABAD2                 <--- kaboom
00000055  call        6CFE2F40 

换句话说:JIT编译器生成显式代码以检查溢出。默认情况下这是关闭的。

答案 1 :(得分:2)

仅当您在源中或作为项目中的设置(这取决于语言)时位于已检查的上下文中时,它才会抛出。其结果是输出不同的IL指令。

这只是arithmetic overflow的一般问题的一个具体示例,并且x86 JIT实现无疑会在任何此类操作之后插入相关标志的检查,并且如果设置了标志则抛出异常的指令。

说明(使用加法作为例子)是:

  • add添加两个数字(包裹溢出)
  • add.ovf添加两个数字并捕获已签名的溢出
  • add.ovf.un添加两个数字并捕获无符号溢出

确实存在一定程度的编译器验证,即发生常量折叠,并且结果值必须适合分配的变量。其他静态分析措施是可能的,但可以捕获的内容有限制。

如果您希望查看发出的JIT代码,只需在混合模式下调试相关代码,并像正常程序一样查看反汇编,堆栈和寄存器。或者去看看ngen图像(由于格式易于改变,这很棘手)。

请注意,通过VS执行此操作,您可能希望正常启动程序(在发布模式下),然后附加调试器,因为JIT的结果会有所不同,具体取决于是否连接了调试器以及是否标记了程序集不允许优化(调试版本的默认设置)