众所周知并且爱.NET每次整数溢出时都会抛出IntegerOverflow
异常。我认为这是一件非常好的事情。
但我不知道他们是如何做到这一点的。 x86不会捕获整数溢出,如果其他架构允许人们这样做,我会感到惊讶。我在x86中找到的最佳解决方案是在每次算术运算后都输入“INTO”指令。但我认为这会导致明显放缓。
他们可以在编译器中进行一些静态检查,以避免在可以证明操作不能溢出的情况下。但是当编译器无法确定操作的结果时,性能关键的内部循环呢?
我试着查看Mono来源,但我找不到他们进行这些检查的地方。
那么有谁知道他们真正做了什么?我真的很想知道。
旁注:有没有办法看到.NET JITC发出的x86代码?
答案 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实现无疑会在任何此类操作之后插入相关标志的检查,并且如果设置了标志则抛出异常的指令。
说明(使用加法作为例子)是:
确实存在一定程度的编译器验证,即发生常量折叠,并且结果值必须适合分配的变量。其他静态分析措施是可能的,但可以捕获的内容有限制。
如果您希望查看发出的JIT代码,只需在混合模式下调试相关代码,并像正常程序一样查看反汇编,堆栈和寄存器。或者去看看ngen图像(由于格式易于改变,这很棘手)。
请注意,通过VS执行此操作,您可能希望正常启动程序(在发布模式下),然后附加调试器,因为JIT的结果会有所不同,具体取决于是否连接了调试器以及是否标记了程序集不允许优化(调试版本的默认设置)