Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

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:

  1. 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?
  2. In MethodB, why is L_0003 necessary?
like image 418
cm007 Avatar asked Mar 22 '13 22:03

cm007


2 Answers

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.

like image 114
Hans Passant Avatar answered Nov 09 '22 00:11

Hans Passant


All of what you see is because you're compiling in Debug mode. The redundant jumps and nops are disabled optimization passes as well as debugging support (I believe).

Compile in Release mode.

like image 28
usr Avatar answered Nov 08 '22 23:11

usr