2015-03-10 8 views
2

Я просто пытаюсь попасть в ИЛ, потому что я работаю с инъекцией кода. Я должен анализировать код и охватывать различные случаи.ИЛ-сравнение наоборот

К сожалению, это не работает, чтобы вставить вызов метода в конце, если последние инструкции находятся внутри if-предложения, потому что тогда вызов содержится в paranthesis.

Теперь я анализирую if-код, переводяемый в IL, и я немного смущен тем, как это делается. Очевидно, компилятор меняет if. Это из-за соображений производительности? Если да, то насколько это улучшает производительность?

Смотрите сами:

 string test; 
     Random rnd = new Random(); 
     bool b = rnd.Next(0, 10) == 3; 
     if (b) 
     { 
      // TRUE 
      test = "True branch"; 
      // END TRUE 
     } 
     else 
     { 
      // FALSE 
      test = "False branch"; 
      //END FALSE 
     } 

и это выход:

IL_0000: nop 
    IL_0001: newobj instance void [mscorlib]System.Random::.ctor() 
    IL_0006: stloc.1 
    IL_0007: ldloc.1 
    IL_0008: ldc.i4.0 
    IL_0009: ldc.i4.s 10 
    IL_000b: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32) 
    IL_0010: ldc.i4.3 
    IL_0011: ceq 
    IL_0013: stloc.2 
    IL_0014: ldloc.2 
    IL_0015: ldc.i4.0 
    IL_0016: ceq 
    IL_0018: stloc.3 
    IL_0019: ldloc.3 
    IL_001a: brtrue.s IL_0026 

    IL_001c: nop 
    IL_001d: ldstr "True branch" 
    IL_0022: stloc.0 
    IL_0023: nop 
    IL_0024: br.s IL_002e 

    IL_0026: nop 
    IL_0027: ldstr "False branch" 
    IL_002c: stloc.0 
    IL_002d: nop 

    IL_002e: ret 

Как вы можете видеть, после сравнения случайного результата с сопзЬ 3 он делает Comparision против 0 снова и таким образом отменяет результат, который эквивалентен if (false).

Какая у этого причина? Разве это не так результативно, так как вам нужны дополнительные инструкции? Всегда ли это происходит?

+0

Вы смотрите версию отладки. Измените его на версию выпуска, и он использует 'brfalse.s' – xanatos

+0

. Нет' 'cne', поэтому может быть использовано' ceq'; но тогда возникает вопрос, почему «brfalse» вместо «brtrue» в RELEASE. Оба сравнивают флаг и будут JIT до одной инструкции почти во всех наборах инструкций CPU. В этом случае, вероятно, это был просто выбор, который в какой-то момент сделал один блок кода для создания одного типа сравнения вместо кода для выбора между двумя разными типами сравнения. Я не верю, что есть ответ на этот вопрос. –

+0

@Peter Технически версия Debug добавляет четыре инструкции и дополнительное местоположение стека IL_0015, IL_0016, IL_0018, IL_0019 и расположение стека .3, но, будучи инструкциями Debug IL, я думаю, что это не настоящая проблема. В то время как JITting они могут быть сопоставлены с образцом и удалены – xanatos

ответ

1

Вы смотрите версию отладки. Измените его на версии, и он использует brfalse.s

IL_0000: newobj instance void [mscorlib]System.Random::.ctor() 
IL_0005: stloc.1 
IL_0006: ldloc.1 
IL_0007: ldc.i4.0 
IL_0008: ldc.i4.s 10 
IL_000a: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32) 
IL_000f: ldc.i4.3 
IL_0010: ceq 
IL_0012: stloc.2 
IL_0013: ldloc.2 
IL_0014: brfalse.s IL_001e 

IL_0016: ldstr "True branch" 
IL_001b: stloc.0 
IL_001c: br.s IL_0024 

IL_001e: ldstr "False branch" 
IL_0023: stloc.0 

Я добавил Console.WriteLine, в противном случае переменная test была удалена.

IL_0024: ldloc.0 
IL_0025: call void [mscorlib]System.Console::WriteLine(string) 
IL_002a: ret 

Так различия между отладки и выпуска являются:

// Debug 
IL_0015: ldc.i4.0 
IL_0016: ceq 
IL_0018: stloc.3 
IL_0019: ldloc.3 
IL_001a: brtrue.s IL_0026 

против

// Release 
IL_0014: brfalse.s IL_001e 

Так четыре дополнительные инструкции для отладочной версии, и "обратный", если.

Сначала я скажу, что компилятор C# пытается сохранить код в том же порядке, в котором он написан. Итак, сначала «истинная» ветвь, затем «ложная» ветвь.

Хорошо ... Я делаю hypotesis ...

Допустим, что проблема находится в режиме отладки ... В режиме отладки код должен быть многословным ... очень многословен. Так

if (b) 

переводится на

if (b == true) 

печально true это "ничего-но-0", так что проще написать

if (!(b == false)) 

потому что false является "0".Но это то, что написано в режиме отладки :-) Только режим отладки использует переменную временную

в

// bool temp = b == false; 
IL_0015: ldc.i4.0 
IL_0016: ceq 
IL_0018: stloc.3 
IL_0019: ldloc.3 

и

// if (temp) // go to else branch 
IL_001a: brtrue.s IL_0026 
+0

Код в ветке отладки в том же порядке, как и указано. –

+1

Настоящая разница в том, что булевая переменная была оптимизирована. Это единственная причина для отладки с использованием brtrue и выпуска с использованием brfalse. Если вы используете код сборки release на if с логическим, который не может быть оптимизирован, тогда я предскажу, что вы увидите сравнение с нулем, за которым следует brtrue. –

+0

Он мог бы использовать 'brtrue'; Я думаю, что вопрос OPs - почему он не ... –

0

Компилятор не сторнируются ничего. Обратите внимание, что две ветви инструкции if отображаются в том же порядке в IL, что и в исходном коде. Вы можете видеть это по порядку двух строк.

Использование brtrue является просто естественным ИЛ для ветвления, когда логическое значение ложно. Тестирование логического значения для истины означает сравнение его с 0. Значение 0 является ложным, все остальное считается истинным.

Итак, компилятор испускает IL для сравнения с 0. Если это сравнение истинно, то есть если логическое значение имеет порядковое значение 0, то логическое значение false. Итак, ветвь, равная нулю, которая есть у вас здесь, означает ветвь, если boolean - false. И это ceq против 0, затем brtrue.

При этом стоит отметить, что при компиляции для отладочной производительности это не проблема. Компилятор хочет написать код, чтобы позволить отладчику проверять переменные. Если вы заинтересованы в производительности, вам нужно взглянуть на IL из сборки релиза. Когда вы это сделаете, вы увидите совершенно другой код.

+0

Кажется, не отвечает на вопрос. –

+0

@Peter вы понимаете, что тестирование bool для нуля такое же, как тестирование, если оно ложно? –

+0

* temp * - это IL_0016: ceq, IL_0018: stloc.3, IL_0019: ldloc.3, поэтому местоположение 3 – xanatos

 Смежные вопросы

  • Нет связанных вопросов^_^