Dar*_*xis 6 c# debugging compiler-optimization visual-studio
Debug尽管Optimize code禁用了某些 C# 代码,但我还是在模式下进行了优化。
代码
namespace Test
{
internal class Program
{
public class Test
{
public void TestMethod(decimal x, out decimal result)
{
result = x / 100m;
//Console.WriteLine($"{x} {result}");
result++;
//Console.WriteLine($"{x} {result}");
}
}
private static void Main()
{
var x = new Test();
x.TestMethod(12300m, out _);
}
}
}
Run Code Online (Sandbox Code Playgroud)
调试时,我可以看到以下内容:
正如您在第二步中看到的,x和result变量都被修改了,但唯一预计要修改的是result.
现在对这个问题进行一些分析。我的猜测是它可能是由两件事引起的:
如果它是 Visual Studio 调试器中的错误,那么为什么取消注释Console.WriteLine代码可以解决此问题?
如果优化代码的是编译器,那么为什么它在 dotPeek 反编译源中不可见?CLR 或其他东西是否有可能在运行时优化代码?dotPeek反编译的汇编源代码如下:
// Decompiled with JetBrains decompiler
// Type: Test.Program
// Assembly: Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 010328D8-C177-4463-81CD-43CDDFF608A4
// Assembly location: XXX
using System;
namespace Test
{
internal class Program
{
private static void Main()
{
new Program.Test().TestMethod(new Decimal(12300), out Decimal _);
}
public class Test
{
public void TestMethod(Decimal x, out Decimal result)
{
result = x / new Decimal(100);
++result;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试过但还没有解决这个问题:
Optimize code标志,构建解决方案,取消选中它,再次构建解决方案(在/sf/answers/2190804031/ 中建议).vs目录编辑1:
这是 MSIL 代码
.method public hidebysig instance void TestMethod(valuetype [mscorlib]System.Decimal x,
[out] valuetype [mscorlib]System.Decimal& result) cil managed
{
// Code size 38 (0x26)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.2
IL_0002: ldarg.1
IL_0003: ldc.i4.s 100
IL_0005: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
IL_000a: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Division(valuetype [mscorlib]System.Decimal,
valuetype [mscorlib]System.Decimal)
IL_000f: stobj [mscorlib]System.Decimal
IL_0014: ldarg.2
IL_0015: ldarg.2
IL_0016: ldobj [mscorlib]System.Decimal
IL_001b: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Increment(valuetype [mscorlib]System.Decimal)
IL_0020: stobj [mscorlib]System.Decimal
IL_0025: ret
} // end of method Test::TestMethod
Run Code Online (Sandbox Code Playgroud)
编辑2:
@HansPassant 感谢您的评论,您提到此问题特定于 x64。好吧,我已经检查过Prefer 32-bit,问题已经解决了,所以它一定是x64的问题!我在内存视图打开的情况下再次调试了该应用程序。我们可以看到内存中的两个变量都发生了变化,因此这可能是您提到的 x64 代码生成中的一个错误。我现在要调试 x64 代码...
编辑 3(最终?):
我已经调试了 x64 代码,结果发现运行时生成了优化的 x64 代码......
下面是两种情况下生成的 x64 汇编代码,一种System.Console.WriteLine是在被调用时(代码未优化),一种System.Console.WriteLine是在被注释时(代码不应优化但已优化):
With System.Console.WriteLine calls:
result = x / 100m;
00007FFD078809F7 lea rcx,[rbp+0D8h]
00007FFD078809FE vxorps xmm0,xmm0,xmm0
00007FFD07880A03 vmovdqu xmmword ptr [rcx],xmm0
00007FFD07880A08 lea rcx,[rbp+0D8h]
00007FFD07880A0F mov edx,64h
00007FFD07880A14 call 00007FFD64B42280 // System.Decimal..ctor(Int32) // new Decimal(100)
00007FFD07880A19 mov rcx,qword ptr [rbp+120h] // rcx = &result
00007FFD07880A20 mov qword ptr [rbp+0D0h],rcx // [rbp+0D0h] = rcx -> &result
00007FFD07880A27 lea rcx,[rbp+0C0h] // ?
00007FFD07880A2E mov qword ptr [rbp+70h],rcx // ?
00007FFD07880A32 mov rcx,qword ptr [rbp+118h] // rcx = &x
00007FFD07880A39 vmovdqu xmm0,xmmword ptr [rcx] // xmm0 = rcx -> x <--- Here we copy 'x' value to xmm0
00007FFD07880A3E vmovdqu xmmword ptr [rbp+88h],xmm0 // [rbp+88h] = xmm0 -> x <--- Here we copy xmm0 ('x' value) to [rbp+88h]
00007FFD07880A47 vmovdqu xmm0,xmmword ptr [rbp+0D8h] // xmm0 = copy of 100m
00007FFD07880A50 vmovdqu xmmword ptr [rbp+78h],xmm0 // [rbp+78h] = xmm0 -> copy of 100m
00007FFD07880A56 mov rcx,qword ptr [rbp+70h] // ?
00007FFD07880A5A lea rdx,[rbp+88h] // rdx = [rbp+88h] -> copy of 'x' as first op_Division arg
00007FFD07880A61 lea r8,[rbp+78h] // R8 = [rbp+78h] -> 100m as second op_Division arg
00007FFD07880A65 call 00007FFD64B440A0 // Call System.Decimal.op_Division(System.Decimal, System.Decimal)
00007FFD07880A6A mov rdx,qword ptr [rbp+0D0h]
00007FFD07880A71 vmovdqu xmm0,xmmword ptr [rbp+0C0h]
00007FFD07880A7A vmovdqu xmmword ptr [rdx],xmm0
With System.Console.WriteLine calls commented:
result = x / 100m;
00007FFD078909F7 lea rcx,[rbp+88h]
00007FFD078909FE vxorps xmm0,xmm0,xmm0
00007FFD07890A03 vmovdqu xmmword ptr [rcx],xmm0
00007FFD07890A08 lea rcx,[rbp+88h]
00007FFD07890A0F mov edx,64h
00007FFD07890A14 call 00007FFD64B42280 // System.Decimal..ctor(Int32) // new Decimal(100)
00007FFD07890A19 mov rcx,qword ptr [rbp+0D0h] // rcx = &result
00007FFD07890A20 mov qword ptr [rbp+80h],rcx // [rbp+80h] = rcx -> &result
00007FFD07890A27 lea rcx,[rbp+70h] // ?
00007FFD07890A2B mov qword ptr [rbp+40h],rcx // ?
00007FFD07890A2F mov rcx,qword ptr [rbp+0C8h] // rcx = &x
00007FFD07890A36 mov qword ptr [rbp+38h],rcx // [rbp+38h] = rcx -> &x
00007FFD07890A3A vmovdqu xmm0,xmmword ptr [rbp+88h] // xmm0 = copy of 100m
00007FFD07890A43 vmovdqu xmmword ptr [rbp+48h],xmm0 // [rbp+48h] = xmm0 -> copy of 100m
00007FFD07890A49 mov rcx,qword ptr [rbp+40h] // ?
00007FFD07890A4D mov rdx,qword ptr [rbp+38h] // rdx = [rbp+38h] = &x -> 'x' instance address as first op_Division arg
00007FFD07890A51 lea r8,[rbp+48h] // r8 = [rbp+48h] -> copy of 100m as second op_Division arg
00007FFD07890A55 call 00007FFD64B440A0 // Call System.Decimal.op_Division(System.Decimal, System.Decimal)
00007FFD07890A5A mov rcx,qword ptr [rbp+80h]
00007FFD07890A61 vmovdqu xmm0,xmmword ptr [rbp+70h]
00007FFD07890A67 vmovdqu xmmword ptr [rcx],xmm0
Run Code Online (Sandbox Code Playgroud)
如您所见,它们很相似,但第一个将x值复制到新的内存位置:
00007FFD07880A39 vmovdqu xmm0,xmmword ptr [rcx] // xmm0 = rcx -> x <--- Here we copy 'x' value to xmm0
00007FFD07880A3E vmovdqu xmmword ptr [rbp+88h],xmm0 // [rbp+88h] = xmm0 -> x <--- Here we copy xmm0 ('x' value) to [rbp+88h]
Run Code Online (Sandbox Code Playgroud)
然后将其传递给System.Decimal.op_Division(System.Decimal, System.Decimal)函数。但是第二个不复制它,直接传递它的引用;它缺少上面的两个说明。
我已经提交了一个错误,正如@HansPassant 所建议的那样,并带有指向此 SO 问题的链接。链接:https : //developercommunity.visualstudio.com/content/problem/992021/c-code-being-optimized-in-debug-mode-with-optimize.html
| 归档时间: |
|
| 查看次数: |
468 次 |
| 最近记录: |