Dima Dima - 1 month ago 13
C# Question

What is the point of nop in CIL

So I wrote the following code in C#.

class Test
{
int a;
System.IO.StreamReader reader;

public Test()
{
a = 5;
reader = new System.IO.StreamReader(String.Empty);
}
}


And the constructor of the class in IL looks like this

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 33 (0x21)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldc.i4.5
IL_000a: stfld int32 Test2.Test::a
IL_000f: ldarg.0
IL_0010: ldsfld string [mscorlib]System.String::Empty
IL_0015: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_001a: stfld class [mscorlib]System.IO.StreamReader Test2.Test::reader
IL_001f: nop
IL_0020: ret
} // end of method Test::.ctor


There are 3
nop
commands. (Which as I know stands for no operation). What is the need of those commands. I mean what would be the difference if there was no command at all instead of
nop

Answer

They are used by the C# compiler when it writes the .pdb file for your program. Which contains debugging info, which includes file+line number info for your code. The debugger uses this to find the machine code where it needs to inject an INT 3 instruction to get the program to stop executing when you set a breakpoint. The jitter emits a NOP machine code instruction for each Opcodes.Nop in the MSIL.

The first nop is used when you set a breakpoint on public Test(). Note that it is injected after the base constructor call so that the this variable becomes valid in the Auto/Locals/Watch debugging windows.

The second nop is used when you set a breakpoint on the first { curly brace. That line generates no code at all so there's a hard need for a fake MSIL instruction.

Same story for the third nop, generated for the last } curly brace. When you set a breakpoint on that one then you can inspect the method return value (if any). Visible indirectly in the Debug + Windows + Registers window. Improved in VS2013.

So this just aids in debugging your program, they make breakpoints act predictably. Those NOPs are not generated when you build the Release configuration of your program. One big reason why a C# project has a Debug and a Release configuration. You can still debug a Release build, it is however a pretty confounding experience that makes you doubt your sanity :)