In IL code, why is there not a nop opcode in a given situation? Why is there a br.s opcode in a given situation?

.net, .net-2.0, cil, opcode

Solution

The C# compiler emits a NOP instruction at a curly brace. Which makes it a lot easier to set breakpoints in your code. The debugger only permits setting a breakpoint on code and a curly brace doesn't normally produce any code. So this is just a simple debugging aid, these NOPs won't get generated in the release build.

The BR.S instruction is a minor flaw in the compiler, it doesn't have a peephole optimizer to get rid of these kind of extraneous instructions. In general, it is not the job of the C# compiler to optimize code, that's done by the jitter. Which will readily and easily remove the instruction.

Problem

Suppose I have the following code: ``` 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; } } ``` The generated IL code from compiling with Visual Studio 2010 as a .NET 2.0 assembly is the following: ``` .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 } ``` My questions are the following: - In MethodA, why is there not a `nop` code between `L_0006` and `L_0007`? - Since `L_0001` to `L_0006` are distinct from `L_0007` to `L_0009`, why is there no `nop` opcode? - In MethodB, why is `L_0003` necessary?

Original source