IL 代码,有人帮我解释一下为什么 ldarg.0 出现两次?

IL code, Someone get me explain why ldarg.0 appear twice?

这是c#代码

class SimpleIL { 
        private int f = 2; 
        public void M1() { M2(f); } 
        public void M2(Object p) { Console.WriteLine(p); } 
}

这是M1方法的IL

 IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.0
  IL_0003:  ldfld      int32 ConsoleApplication1.SimpleIL::f
  IL_0008:  box        [mscorlib]System.Int32
  IL_000d:  call       instance void ConsoleApplication1.SimpleIL::M2(object)
  IL_0012:  nop
  IL_0013:  ret

我的问题是:为什么两次 ldarg.0?

Ldarg.0 在实例方法中是 this

一个是获取f,一个是调用M2.

(技术上首先使用第二个,因为当访问 f 时它位于堆栈的顶部)

第二个也可以放在调用之前,但这并不重要 - 它只需要在调用时位于堆栈顶部即可。

第一个 ldarg.0this 指针作为 M2 调用的 this 参数加载到堆栈上。

第二个 ldarg.0 加载 this 指针以访问 f 字段。

IL 代码可以这样分组:

IL_0000:  nop

    IL_0001:  ldarg.0

        // get the value for the parameter
        IL_0002:  ldarg.0
        IL_0003:  ldfld      int32 ConsoleApplication1.SimpleIL::f
        IL_0008:  box        [mscorlib]System.Int32

    // call "this.M2(...)", this is already on the stack from before
    IL_000d:  call       instance void ConsoleApplication1.SimpleIL::M2(object)

IL_0012:  nop
IL_0013:  ret

要使用 IL 调用方法,您可以这样做:

load instance reference on the stack
load argument values on the stack
call method

这里先将"instance reference"加载到栈中,然后添加获取参数值的代码,其中还涉及到获取栈上的实例引用,然后才是使用实例引用的实际调用.