Dot-Net

在 IL 程式碼中,為什麼在給定情況下沒有 nop 操作碼?為什麼在給定情況下會有 br.s 操作碼?

  • March 22, 2013

假設我有以下程式碼:

public class Class1
{
   private Class2 obj;

   public void MethodA()
   {
       var class2 = new Class2();
       class2.PropertyI = 2;
       obj = MethodB(class2);
   }

   public Class2 MethodB(Class2 class2)
   {
       return class2;
   }
}

public class Class2
{
   public int PropertyI { get; set; }
}

使用 Visual Studio 2010 編譯為 .NET 2.0 程序集生成的 IL 程式碼如下:

.method public hidebysig instance void MethodA() cil managed
{
   .maxstack 3
   .locals init (
       [0] class ClassLibrary1.Class2 class2)
   L_0000: nop 
   L_0001: newobj instance void ClassLibrary1.Class2::.ctor()
   L_0006: stloc.0 
   L_0007: ldloc.0 
   L_0008: ldc.i4.2 
   L_0009: callvirt instance void ClassLibrary1.Class2::set_PropertyI(int32)
   L_000e: nop 
   L_000f: ldarg.0 
   L_0010: ldarg.0 
   L_0011: ldloc.0 
   L_0012: call instance class ClassLibrary1.Class2 ClassLibrary1.Class1::MethodB(class ClassLibrary1.Class2)
   L_0017: stfld class ClassLibrary1.Class2 ClassLibrary1.Class1::obj
   L_001c: ret 
}

.method public hidebysig instance class ClassLibrary1.Class2 MethodB(class ClassLibrary1.Class2 class2) cil managed
{
   .maxstack 1
   .locals init (
       [0] class ClassLibrary1.Class2 CS$1$0000)
   L_0000: nop 
   L_0001: ldarg.1 
   L_0002: stloc.0 
   L_0003: br.s L_0005
   L_0005: ldloc.0 
   L_0006: ret 
}

我的問題如下:

  1. 在 MethodA 中,為什麼和之間沒有nop程式碼? L_0006``L_0007
  • 既然L_0001to與toL_0006不同,為什麼沒有操作碼?L_0007``L_0009``nop
  1. 在 MethodB 中,為什麼L_0003需要?

C# 編譯器在大括號處發出 NOP 指令。這使得在程式碼中設置斷點變得容易得多。調試器只允許在程式碼上設置斷點,大括號通常不會產生任何程式碼。所以這只是一個簡單的調試幫助,這些 NOP 不會在發布版本中生成。

BR.S 指令是編譯器中的一個小缺陷,它沒有一個窺孔優化器來擺脫這些無關的指令。通常,優化程式碼不是 C# 編譯器的工作,而是由jitter 完成的。這將輕鬆輕鬆地刪除指令。

引用自:https://stackoverflow.com/questions/15580802