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.