This is the c# code
class SimpleIL {
private int f = 2;
public void M1() { M2(f); }
public void M2(Object p) { Console.WriteLine(p); }
}
This is the IL of M1 method
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
My question is: Why twice ldarg.0?
Ldarg.0
is this
in an instance method.
One is to get f
, the other is to call M2
.
(Technically the second is used first as it is at the top of the stack when f
is accessed)
The second could as well be placed just before the call but it doesn't really matter - it just has to be on top of the stack when the call is made.
The IL code can be grouped like this:
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
To call a method using IL you do this:
load instance reference on the stack
load argument values on the stack
call method
Here the "instance reference" was loaded onto the stack first, then code to obtain the parameter value was added, which also involved getting an instance reference on the stack, followed by the actual call that uses the instance reference.
The first ldarg.0
loads the this
pointer as the this
argument for the M2
call onto the stack.
The second ldarg.0
loads the this
pointer for accessing the f
field.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With