在Visual Studio中運行發行版並在Visual Studio外部運行發行版時,如下代碼提供了不一樣的輸出。 我正在使用Visual Studio 2008並以.NET 3.5爲目標。 我也嘗試過.NET 3.5 SP1。 oop
當在Visual Studio外部運行時,JIT應該啓動。或者(a)C#中有一些微妙的東西我缺失或者(b)JIT其實是錯誤的。 我懷疑JIT可能出錯,但我已經沒有其餘可能性...... 優化
在Visual Studio中運行時的輸出: this
0 0, 0 1, 1 0, 1 1,
在Visual Studio外部運行發佈時的輸出: spa
0 2, 0 2, 1 2, 1 2,
是什麼緣由? 調試
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test { struct IntVec { public int x; public int y; } interface IDoSomething { void Do(IntVec o); } class DoSomething : IDoSomething { public void Do(IntVec o) { Console.WriteLine(o.x.ToString() + " " + o.y.ToString()+","); } } class Program { static void Test(IDoSomething oDoesSomething) { IntVec oVec = new IntVec(); for (oVec.x = 0; oVec.x < 2; oVec.x++) { for (oVec.y = 0; oVec.y < 2; oVec.y++) { oDoesSomething.Do(oVec); } } } static void Main(string[] args) { Test(new DoSomething()); Console.ReadLine(); } } }
我將您的代碼複製到新的控制檯應用程序中。 rest
因此它是x86 JIT錯誤地生成代碼。 已經刪除了關於循環從新排序的原始文本等。此處的一些其餘答案已經確認JIT在x86上不正確地展開循環。 code
要解決此問題,您能夠將IntVec的聲明更改成類,而且它適用於全部類型。 排序
認爲這須要繼續MS Connect .... rem
-1到微軟! string
我相信這是一個真正的JIT編譯錯誤。 我會向微軟報告,看看他們說了什麼。 有趣的是,我發現x64 JIT沒有一樣的問題。
這是我對x86 JIT的閱讀。
// save context 00000000 push ebp 00000001 mov ebp,esp 00000003 push edi 00000004 push esi 00000005 push ebx // put oDoesSomething pointer in ebx 00000006 mov ebx,ecx // zero out edi, this will store oVec.y 00000008 xor edi,edi // zero out esi, this will store oVec.x 0000000a xor esi,esi // NOTE: the inner loop is unrolled here. // set oVec.y to 2 0000000c mov edi,2 // call oDoesSomething.Do(oVec) -- y is always 2!?! 00000011 push edi 00000012 push esi 00000013 mov ecx,ebx 00000015 call dword ptr ds:[002F0010h] // call oDoesSomething.Do(oVec) -- y is always 2?!?! 0000001b push edi 0000001c push esi 0000001d mov ecx,ebx 0000001f call dword ptr ds:[002F0010h] // increment oVec.x 00000025 inc esi // loop back to 0000000C if oVec.x < 2 00000026 cmp esi,2 00000029 jl 0000000C // restore context and return 0000002b pop ebx 0000002c pop esi 0000002d pop edi 0000002e pop ebp 0000002f ret
這看起來像是對我不利的優化......
這是一個JIT優化器錯誤。 它展開內部循環但不正確更新oVec.y值:
for (oVec.x = 0; oVec.x < 2; oVec.x++) { 0000000a xor esi,esi ; oVec.x = 0 for (oVec.y = 0; oVec.y < 2; oVec.y++) { 0000000c mov edi,2 ; oVec.y = 2, WRONG! oDoesSomething.Do(oVec); 00000011 push edi 00000012 push esi 00000013 mov ecx,ebx 00000015 call dword ptr ds:[00170210h] ; first unrolled call 0000001b push edi ; WRONG! does not increment oVec.y 0000001c push esi 0000001d mov ecx,ebx 0000001f call dword ptr ds:[00170210h] ; second unrolled call for (oVec.x = 0; oVec.x < 2; oVec.x++) { 00000025 inc esi 00000026 cmp esi,2 00000029 jl 0000000C
當你讓oVec.y增長到4時,這個bug就會消失,那就是要打開的次數過多。
一個解決方法是:
for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { oDoesSomething.Do(new IntVec(x, y)); } }
更新:2012年8月從新檢查,此錯誤已在版本4.0.30319抖動中修復。 但仍然存在於v2.0.50727抖動中。 在這麼久以後,他們彷佛不太可能在舊版本中解決這個問題。