Free mag vol1 | Page 734

CHAPTER 18  UNDERSTANDING CIL AND THE ROLE OF DYNAMIC ASSEMBLIES Mapping Parameters to Local Variables in CIL You have already seen how to declare local variables in raw CIL using the .locals init directive; however, you have yet to see exactly how to map incoming parameters to local methods. Consider the following static C# method: public static int Add(int a, int b) { return a + b; } This innocent-looking method has a lot to say in terms of CIL. First, the incoming arguments (a and b) must be pushed onto the virtual execution stack using the ldarg (load argument) opcode. Next, the add opcode will be used to pop the next two values off the stack and find the summation, and store the value on the stack yet again. Finally, this sum is popped off the stack and returned to the caller via the ret opcode. If you were to disassemble this C# method using ildasm.exe, you would find numerous additional tokens injected by csc.exe, but the crux of the CIL code is quite simple. .method public hidebysig int32 b) cil managed { .maxstack 2 ldarg.0 // Load "a" ldarg.1 // Load "b" add // Add both ret } static int32 Add(int32 a, onto the stack. onto the stack. values. The Hidden this Reference Notice that the two incoming arguments (a and b) are referenced within the CIL code using their indexed position (index 0 and index 1), given that the virtual execution stack begins indexing at position 0. One thing to be very mindful of when you are examining or authoring CIL code is that every nonstatic method that takes incoming arguments automatically receives an implicit additional parameter, which is a reference to the current object (think the C# this keyword). Given this, if the Add() method were defined as nonstatic, like so: // No longer static! public int Add(int a, int b) { return a + b; } the incoming a and b arguments are loaded using ldarg.1 and ldarg.2 (rather than the expected ldarg.0 and ldarg.1 opcodes). Again, the reason is that slot 0 actually contains the implicit this reference. Consider the following pseudo-code: // This is JUST pseudo-code! .method public hidebysig static int32 AddTwoIntParams( MyClass_HiddenThisPointer this, int32 a, int32 b) cil managed { ldarg.0 // Load MyClass_HiddenThisPointer onto the stack. ldarg.1 // Load "a" onto the stack. 677