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?

¿Fue útil?

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 aunque SomeMethod es virtual, puede llamarlo directamente con el call instrucción.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top