c# - ¿Por qué el compilador JIT.NET decide no alinear u optimizar las llamadas a métodos estáticos vacíos que no tienen efectos secundarios?
clr compiler-optimization (1)
Creo que estoy observando que el compilador JIT .NET no integra ni optimiza las llamadas a métodos estáticos vacíos que no tienen efectos secundarios, lo cual es un poco sorprendente dado algunos recursos en línea personalizados.
Mi entorno es Visual Studio 2013 en x64, Windows 8.1, .NET Framework 4.5.
Dado este sencillo programa de prueba ( https://ideone.com/2BRCpC )
class Program
{
static void EmptyBody()
{
}
static void Main()
{
EmptyBody();
}
}
Una versión de compilación con optimizaciones del programa anterior produce la siguiente MSIL para Main
y EmptyBody
:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 8
IL_0000: call void Program::EmptyBody()
IL_0005: ret
} // end of method Program::Main
.method private hidebysig static void EmptyBody() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Program::EmptyBody
No es sorprendente que la MSIL contenga una llamada de Main
a EmptyBody
, ya que no se espera que el compilador de C # EmptyBody
o optimice llamadas de esa manera. Sin embargo, pensé que el compilador JIT luego alinearía o optimizaría esa llamada. Pero eso no parece suceder.
Si ejecuto el programa anterior y entro en el depurador en Main
, el ensamblado generado es el siguiente:
00572621 mov ebp,esp
00572623 cmp dword ptr ds:[4320B84h],0
0057262A je 00572631
0057262C call 73E6AF20
00572631 call dword ptr ds:[4321578h]
El puntero de instrucción se establece inmediatamente en la última línea en 00572631, que es la llamada a EmptyBody
. Al entrar en EmptyBody
, se encuentra que el ensamblado generado es
00BD2651 mov ebp,esp
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
00BD2661 nop
00BD2662 pop ebp
00BD2663 ret
El puntero de instrucción se establece inmediatamente en la línea nop
en 00BD2661, que no hace nada, y no puedo adivinar por qué se generó en primer lugar.
Dado que los dos fragmentos de ensamblaje anteriores comparten el mismo encabezado de 4 instrucciones, asumo que es solo la placa de la caldera de entrada de método normal donde se configura la pila y tal. Sin embargo, estoy dispuesto a aprender a saber qué harían estas instrucciones recurrentes:
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
De todos modos, la pregunta principal es: ¿Por qué el compilador JIT produce un ensamblaje que llama al método estático de cuerpo vacío, EmptyBody
?
Después de profundizar un poco más, resulta que puedo responder esta pregunta yo mismo. Como se explica en http://blogs.msdn.com/b/vancem/archive/2006/02/20/535807.aspx , observar el desensamblaje de una versión de lanzamiento optimizada bajo el depurador afectará de forma predeterminada al compilador JIT.
Deseleccionando estos
- ''Suprimir la optimización JIT en la carga del módulo''
- ''Habilitar solo mi código''
en VS> Herramientas> Depuración> General, se mostrará el resultado de compilación JIT "real", que para la llamada a EmptyBody
en mi Main
anterior es la siguiente:
004C2620 ret
Lo que significa que la llamada a EmptyBody
se eliminó por completo, que es lo que se esperaba y el mundo sigue siendo un lugar feliz y un tanto predecible para vivir :)