MSIL: лишняя ветвь

Рассмотрим этот фрагмент C#:

static string input = null;
static string output = null;

static void Main(string[] args)
{
     input = "input";
     output = CallMe(input);
}

public static string CallMe(string input)
{
     output = "output";
     return output;
}

Разборка с помощью Reflector показывает:

.method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 8
        L_0000: nop 
        L_0001: ldstr "input"
        L_0006: stsfld string Reflector_Test.Program::input
        L_000b: ldsfld string Reflector_Test.Program::input
        L_0010: call string Reflector_Test.Program::CallMe(string)
        L_0015: stsfld string Reflector_Test.Program::output
        L_001a: ret 
    }

 .method public hidebysig static string CallMe(string input) cil managed
    {
        .maxstack 1
        .locals init (
            [0] string CS$1$0000)
        L_0000: nop 
        L_0001: ldstr "output"
        L_0006: stsfld string Reflector_Test.Program::output
        L_000b: ldsfld string Reflector_Test.Program::output
        L_0010: stloc.0 
        L_0011: br.s L_0013
        L_0013: ldloc.0 
        L_0014: ret 
    }

Часть, которая меня озадачивает:

L_0010: stloc.0 
L_0011: br.s L_0013
L_0013: ldloc.0 

Он сохраняет элемент, переходит к следующей строке (которая в любом случае была бы выполнена), а затем снова загружает его.

Есть причина для этого?


cil
person rbrayb    schedule 23.03.2009    source источник


Ответы (2)


Это происходит только в Debug, а не в Release. Я подозреваю, что это поможет во время отладки. Это, возможно, позволяет вам отбрасывать точки останова в середине оператора и видеть возвращаемое значение.

Обратите внимание, что релизная версия имеет гораздо более лаконичный IL:

.method private hidebysig static void Main(string[] args) cil managed
{
    .maxstack 8
    L_0000: ldstr "input"
    L_0005: stsfld string Reflector_Test.Program::input
    L_000a: ldsfld string Reflector_Test.Program::input
    L_000f: call string Reflector_Test.Program::CallMe(string)
    L_0014: stsfld string Reflector_Test.Program::output
    L_0019: ret 
}




.method public hidebysig static string CallMe(string input) cil managed
{
    .maxstack 8
    L_0000: ldstr "output"
    L_0005: stsfld string Reflector_Test.Program::output
    L_000a: ldsfld string Reflector_Test.Program::output
    L_000f: ret 
}
person Sam Saffron    schedule 23.03.2009

Я предполагаю, что это шаблонный код для выполнения оператора возврата, компилятор выполняет безусловный переход к последней строке и загружает возвращаемое значение в регистр перед выполнением ret. JIT оптимизирует его лучше, я думаю, что компилятор не беспокоится об оптимизации.

person 1800 INFORMATION    schedule 23.03.2009
comment
Это происходит в режиме выпуска, см. мой ответ - person Sam Saffron; 24.03.2009