registrado kmspico just especifico error depurador depuración depuracion aplicación admite c# jit

c# - kmspico - la aplicación no admite la depuración just in time jit



.NET JIT error potencial? (3)

Copié su código en una nueva aplicación de consola.

  • Construcción de depuración
    • Corrija la salida con el depurador y sin el depurador
  • Cambiado a la versión de lanzamiento
    • Una vez más, corregir la salida en ambas ocasiones
  • Creé una nueva configuración x86 (estoy ejecutando X64 Windows 2008 y estaba usando ''Cualquier CPU'')
  • Construcción de depuración
    • Obtuvo la salida correcta tanto F5 como CTRL + F5
  • Versión de lanzamiento
    • Salida correcta con el depurador adjunto
    • Sin depurador - Obtuvo el resultado incorrecto

Así que es el x86 JIT generando incorrectamente el código. He eliminado mi texto original sobre la reordenación de los bucles, etc. Algunas otras respuestas aquí confirmaron que el JIT está desenrollando el bucle incorrectamente cuando está en x86.

Para solucionar el problema, puede cambiar la declaración de IntVec a una clase y funciona en todos los tipos.

Piensa que esto necesita irse en MS Connect ...

-1 a Microsoft!

El siguiente código da un resultado diferente cuando se ejecuta la versión dentro de Visual Studio, y se ejecuta la versión fuera de Visual Studio. Estoy usando Visual Studio 2008 y apuntando a .NET 3.5. También he intentado .NET 3.5 SP1.

Cuando se ejecuta fuera de Visual Studio, el JIT debería activarse. O bien (a) está ocurriendo algo sutil con C # que me falta o (b) el JIT está realmente en error. Dudo que el JIT pueda salir mal, pero me estoy quedando sin otras posibilidades ...

Salida cuando se ejecuta dentro de Visual Studio:

0 0, 0 1, 1 0, 1 1,

Salida al ejecutar la versión fuera de Visual Studio:

0 2, 0 2, 1 2, 1 2,

¿Cual es la razon?

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(); } } }


Creo que esto está en un error de compilación JIT genuino. Lo reportaría a Microsoft y vería lo que dicen. Curiosamente, encontré que el JIT x64 no tiene el mismo problema.

Aquí está mi lectura del 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

Esto parece una optimización que me salió mal ...


Es un error del optimizador JIT. Se está desenrollando el bucle interno pero no está actualizando el valor de oVec.y correctamente:

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

El error desaparece cuando dejas que OVec.y se incremente a 4, son demasiadas llamadas para desenrollar.

Una solución es la siguiente:

for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { oDoesSomething.Do(new IntVec(x, y)); } }

ACTUALIZACIÓN: revisado nuevamente en agosto de 2012, este error se corrigió en la versión 4.0.30319 jitter. Pero todavía está presente en la v2.0.50727 jitter. Parece poco probable que solucionen esto en la versión anterior después de tanto tiempo.