1

正如我们都知道和喜爱的那样,IntegerOverflow每次整数溢出时,.NET 都会引发异常。我认为这是一件非常好的事情。

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

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

我试图查看 Mono 源代码,但找不到他们进行这些检查的位置。

那么有人知道他们真正在做什么吗?我真的很想知道。

附带说明:有没有办法查看 .NET JITC 发出的 x86 代码?

4

2 回答 2

3

开始调试,右键源代码,转到反汇编。你会看到这样的东西:

      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 编译器生成显式代码来检查溢出。默认情况下这是关闭的。

于 2010-01-12T01:18:32.193 回答
2

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

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

说明(以加法为例)是:

  • add添加两个数字(环绕溢出)
  • add.ovf将两个数字相加并捕获有符号溢出
  • add.ovf.un将两个数字相加并捕获无符号溢出

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

如果您希望查看发出的 JIT 代码,只需在混合模式下调试相关代码,然后像查看普通程序一样查看反汇编、堆栈、寄存器。或者去看看 ngen 图像(这很棘手,因为格式容易改变)。

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

于 2010-01-12T01:13:40.387 回答