【问题标题】:Compilation omits code after fixed blocks in certain methods编译在某些方法中省略了固定块之后的代码
【发布时间】:2014-09-08 17:55:05
【问题描述】:

我们的一个项目的一个类中有以下方法:

private unsafe void SomeMethod()
{
    // Beginning of the method omitted for brevity

    var nv = new Vector4[x];

    fixed (Vector4* vp = nv)
    {
        fixed (float* tp = /* Source float ptr */)
        {
            fixed (double* ap = /* Source double ptr */)
            {
                for (var i = atlArray.Length - 1; i >= 0; --i)
                {
                    vp[((i + 1) << 3) - 2] = new Vector4(tp[i], btt, 0.0f, 1.0f);
                    // Additional Vector4 construction omitted for brevity

                    nttp[i] = new Vector2(tp[i], this.ttvp);
                    nts[i] = string.Format(ap[i], /* etc. */);
                }
            }
        }
    }

    this.ts = nts;
    this.ttp = nttp;
    this.V = nv; // <- This is a property setter
}

我不得不对此进行混淆,但希望它仍然足够清晰,可以了解发生了什么。

在我们开发人员的一台机器上,在调试版本中,C# 编译器会删除在 fixed 块关闭后发生的三个赋值。如果我们尝试在这些行上放置断点,则断点会在应用程序启动时跳到方法的结束大括号。出现在fixed 块和方法结尾之间的代码也会在其他方法中被删除,但令人费解的是,并非所有方法都删除。

经过一些实验,我们发现为受影响的项目启用优化会导致包含缺失的代码。但是,这种变通方法对我们的单元测试失败了——缺少代码,更改受影响项目及其测试项目的优化也无济于事。我们还发现,在最里面的 fixed 语句中移动三个赋值是有效的——在检查 IL 时就很清楚为什么了。

在受影响机器上构建的调试DLL中(关闭优化),在ap出栈后直接出现return op:

IL_03a1:  nop
IL_03a2:  ldc.i4.0
IL_03a3:  conv.u
IL_03a4:  stloc.s    ap
IL_03a6:  ret

这解释了为什么在 stloc 指令之前移动三个分配有效。在我的机器上构建的调试DLL中,返回操作发生在预期的位置,在三个赋值之后:

IL_03a5:  nop
IL_03a6:  ldc.i4.0
IL_03a7:  conv.u
IL_03a8:  stloc.s    ap
IL_03aa:  nop
IL_03ab:  ldc.i4.0
IL_03ac:  conv.u
IL_03ad:  stloc.s    tp
IL_03af:  nop
IL_03b0:  ldc.i4.0
IL_03b1:  conv.u
IL_03b2:  stloc.s    vp
IL_03b4:  ldarg.0
IL_03b5:  ldloc.s    nts
IL_03b7:  stfld      string[] N.B.E.B::ts
IL_03bc:  ldarg.0
IL_03bd:  ldloc.s    nttp
IL_03bf:  stfld      valuetype [SharpDX]SharpDX.Vector2[] N.B.E.B::ttp
IL_03c4:  ldarg.0
IL_03c5:  ldloc.s    nv
IL_03c7:  call       instance void N.B.E.B::set_V(valuetype [SharpDX]SharpDX.Vector4[])
IL_03cc:  nop
IL_03cd:  ret

到目前为止,我们未能产生 SSCCE - 这似乎只在非常特定的情况下表现出来,并且只在我们的一个项目中表现出来。我们检查了两台机器上都使用了相同版本的 Visual Studio、.NET 框架、C# 编译器和 MSBuild。我们检查了其他潜在差异,例如操作系统版本和更新。两台机器上的情况似乎相同(它们是相同型号的笔记本电脑)。坦率地说,我们有点困惑。任何帮助将不胜感激。

【问题讨论】:

    标签: c# visual-studio-2013 il


    【解决方案1】:

    我的同事(其机器受到影响的开发人员)发现构建的诊断输出存在差异 - 它是 C# 编译器。我们认为 MSBuild 正在使用预期位置 (c:\Program Files (x86)\MSBuild\12.0\Bin) 中的 csc.exe,但奇怪的是,它实际上是在C:\Users\[user]\AppData\Local\Microsoft\VisualStudio\12.0\Extensions,版本完全不同。我们不知道那个编译器可执行文件是如何出现的,或者它是如何被 MSBuild 引用的,但是一旦它被删除,MSBuild 就会恢复使用其主 Bin 目录中的 csc.exe 版本,并且代码正在现在构建正确。

    【讨论】:

    • 这不是 Roslyn 编译器吗?我在 C:\Users\Svick\AppData\Local\Microsoft\VisualStudio\12.0\Extensions\2wcdsxyh.slm\rcsc.exe 中有那个。如果是这种情况,您可能想要report this bug to the Roslyn team
    • @svick 这是一个有趣的线索——我会在周一从我的同事那里了解他是否安装了 Roslyn 编译器,如果他安装了这个问题,请向 Roslyn 团队报告。我会回来报告的。
    猜你喜欢
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 2016-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多