.NET JIT潜在的错误? [英] .NET JIT potential error?

查看:125
本文介绍了.NET JIT潜在的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码运行Visual Studio中释放的时候,和运行Visual Studio之外释放出不同的输出。我使用Visual Studio 2008和.NET目标3.5。我也试着.NET 3.5 SP1。



在Visual Studio的外运行时,JIT应该踢。无论是(一)有一些微妙的用C#怎么回事,我'M缺失或(b)该JIT实际上是错误。我怀疑的JIT可以去错了,但我跑出来的其他possiblities的...



输出在Visual Studio中运行时:

  0,
0 1,
1 0,
1,

输出当运行Visual Studio之外发布:

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

这是什么原因

 使用系统?; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

命名空间测试
{
结构INTVEC
{
公众诠释X;
公众诠释Ÿ;
}

接口IDoSomething
{
无效DO(INTVEC O);
}

类的DoSomething:IDoSomething
{
公共无效DO(INTVEC O)
{
Console.WriteLine(oxToString() ++ oyToString()+,);
}
}

类节目
{
静态无效测试(IDoSomething oDoesSomething)
{
INTVEC oVec =新INTVEC ();
为(oVec.x = 0; oVec.x 2; oVec.x ++)
{
为(oVec.y = 0; oVec.y 2; oVec.y ++ )
{
oDoesSomething.Do(oVec);
}
}
}

静态无效的主要(字串[] args)
{
测试(新DoSomething的());
到Console.ReadLine();
}
}
}


解决方案

这是一个JIT优化器的bug。这是展开内部循环,但不能正常更新oVec.y值:

 为(oVec.x = 0; oVec。 X  -  2; oVec.x ++){$​​ b $ b 0000000A异ESI,ESI; oVec.x = 0 
表示(oVec.y = 0; oVec.y 2; oVec.y ++){$​​ B $ B 0000000c MOV EDI,2; oVec.y = 2,错!
oDoesSomething.Do(oVec);
00000011推EDI
00000012推ESI
00000013 MOV ECX,EBX
00000015电话DWORD PTR DS:[00170210h];第一个展开调用
0000001b推EDI;错误!不增加oVec.y
0000001c推ESI
0000001d MOV ECX,EBX
0000001F调用DWORD PTR DS:[00170210h];第二个电话展开
为(oVec.x = 0; oVec.x 2; oVec.x ++){$​​ B $ B 00000025 INC ESI
00000026 CMP ESI,2
00000029 JL 0000000C

当你让oVec.y增量4的错误消失了,这是太多调用解开。



一个解决方法是这样的:

 的for(int x = 0; X  -  2; X ++){$​​ b $ b表示(中间体Y = 0; Y 2; Y ++){$​​ b $ b oDoesSomething.Do(新INTVEC(X,Y)); 
}
}



更​​新:2012年8月重新检查,这个bug固定在版本4.0.30319抖动。但是仍然存在于V2.0.50727抖动。这似乎不大可能,他们会在老版本之后这么久解决这个问题。


The following code gives different output when running the release inside Visual Studio, and running the release outside Visual Studio. I'm using Visual Studio 2008 and targeting .NET 3.5. I've also tried .NET 3.5 SP1.

When running outside Visual Studio, the JIT should kick in. Either (a) there's something subtle going on with C# that I'm missing or (b) the JIT is actually in error. I'm doubtful that the JIT can go wrong, but I'm running out of other possiblities...

Output when running inside Visual Studio:

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

Output when running release outside of Visual Studio:

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

What is the reason?

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

解决方案

It is a JIT optimizer bug. It is unrolling the inner loop but not updating the oVec.y value properly:

      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 

The bug disappears when you let oVec.y increment to 4, that's too many calls to unroll.

One workaround is this:

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

UPDATE: re-checked in August 2012, this bug was fixed in the version 4.0.30319 jitter. But is still present in the v2.0.50727 jitter. It seems unlikely they'll fix this in the old version after this long.

这篇关于.NET JIT潜在的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆