I am mucking around with parsing some IL at the moment, and I just so happened upon the IL generated from a very simple lambda function in my code. The original code looks like this:
((User x) => x.Id == 2)
The IL generated from this C# code looks like so:
IL_0000: ldarg.0
IL_0001: callvirt instance int32 Utilities.Test.User::get_Id()
IL_0006: ldc.i4.2
IL_0007: ceq
IL_0009: stloc.0
IL_000a: br.s IL_000c
IL_000c: ldloc.0
IL_000d: ret
I get most of it - it loads the User parameter 'x' onto the stack, calls the getter of the Id property chucks the result on the stack, chucks a two on the stack, then checks for equality.
So, 'ceq' places this boolean result onto the stack. So this is what I read from addresses IL_0009 onwards:
IL_0009: pop the result of the ceq evaluation off the stack into local var 0
IL_000a: branch 0 instructions forward
IL_000c: load the local var 0 back onto the stack
IL_000d: return
I can't see how instructions 9 through C are relevant, is there something that the seemingly pointless "branch 0" call is doing that I am completely misunderstanding here? Is there some side-effect of branching that is useful here?
Any help is appreciated :)
EDIT: I keep reading this and catch myself thinking it's native code, I forget these instructions aren't executed directly on the CPU. So maybe a branch command in IL is replaced by the JITter with some x86 instruction like 'jmp' that clears flags registers set in the ceq function that could cause problems after returning from the function... like it's 'cleaning up after itself' with the side-effects of a jump.
Really I have no idea, I'm clutching at straws here...