¿Un .maxstack más grande cuando no se almacena una referencia?
-
19-09-2019 - |
Pregunta
No soy un maestro de IL de ningún tipo, solo lo uso a veces para comprobar qué hace el compilador con el código que escribo.Una cosa que me he estado preguntando es por qué .maxstack
obtiene el valor que obtiene a veces.Considere la siguiente clase:
public class Sample
{
public void SomeMethod(){}
}
Entonces tengo un programa como este:
private static void Main(string[] args)
{
Sample sample = new Sample();
sample.SomeMethod();
}
El código anterior proporciona el siguiente IL (versión compilada):
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 1
.locals init ([0] class ConsoleApplication1.Sample sample)
IL_0000: newobj instance void ConsoleApplication1.Sample::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void ConsoleApplication1.Sample::SomeMethod()
IL_000c: ret
} // end of method Program::Main
Ahora, si cambio el código del programa a esto:
private static void Main(string[] args)
{
new Sample().SomeMethod();
}
...da como resultado el siguiente código IL:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void ConsoleApplication1.Sample::.ctor()
IL_0005: call instance void ConsoleApplication1.Sample::SomeMethod()
IL_000a: ret
} // end of method Program::Main
El segundo código IL es más corto, como se esperaba.Pero lo que me da un poco de curiosidad es por qué .maxstack
¿Tengo 8 en el segundo ejemplo de código, pero 1 en el primero?¿Por qué el segundo código hace que el sistema reserve una pila más grande para la operación?
Solución
La representación binaria del encabezado de un método tiene un "formato pequeño" y un "formato grueso".El encabezado pequeño ocupa menos bytes y se puede utilizar siempre que se cumplan las siguientes condiciones:
- Pila máxima <= 8
- Sin manejo de excepciones
- Sin variables locales
- Tamaño del código < 64 bytes
Su cambio permitió que el compilador usara este formulario, y cuando se encuentra un encabezado pequeño, siempre se supone que usa una pila máxima de 8.
La referencia es ECMA-335 §25.4.2
En otros comentarios De particular interés para mí es el hecho de que en una versión de lanzamiento (según su nota en el OP) produjeron un código diferente, donde la forma abreviada es más pequeña y más rápida.¿Qué versión de C# estás usando?Esperaría que las versiones posteriores aprovecharan esta optimización obvia:
- La variable local podría eliminarse sin cambiar la semántica.
- Cuando la variable local no está presente, el compilador sabe que el tipo concreto del valor es exactamente
Sample
, así que aunqueSomeMethod
es virtual, puede llamarlo directamente con elcall
instrucción.