Pregunta

Estoy jugando con F # en VS2010 beta2, y como soy nuevo en F #, simplemente elegí uno de los ejemplos comunes y seguí adelante e implementé una función factorial como:

let rec factorial n =
  if n <= 1 then 1 else n * factorial (n - 1);;

Si compilo esto y miro el código generado en Reflector, obtengo el código C # correspondiente:

public static int Factorial(int n) {
   if (n <= 1) 
      return 1;

      return n * Factorial(n - 1);
}

Entonces, si compilo la representación en C # de Reflector del código F #, esperaría obtener una IL idéntica.

Sin embargo, si compilo estos dos fragmentos en modo de lanzamiento y comparo el IL generado, son diferentes (son funcionalmente idénticos, pero aún así difieren un poco).

La implementación de C # se compila para:

.method public hidebysig static int32 Factorial(int32 n) cil managed
{
   .maxstack 8
   L_0000: ldarg.0 
   L_0001: ldc.i4.1 
   L_0002: bgt.s L_0006
   L_0004: ldc.i4.1 
   L_0005: ret 
   L_0006: ldarg.0 
   L_0007: ldarg.0 
   L_0008: ldc.i4.1 
   L_0009: sub 
   L_000a: call int32 TestApp.Program::Factorial(int32)
   L_000f: mul 
   L_0010: ret 
}

La implementación de F # se compila para:

.method public static int32 factorial(int32 n) cil managed
{
   .maxstack 5        <=== Different maxstack
   L_0000: nop        <=== nop instruction?
   L_0001: ldarg.0 
   L_0002: ldc.i4.1 
   L_0003: bgt.s L_0007
   L_0005: ldc.i4.1 
   L_0006: ret 
   L_0007: ldarg.0 
   L_0008: ldarg.0 
   L_0009: ldc.i4.1 
   L_000a: sub 
   L_000b: call int32 FSharpModule::factorial(int32)
   L_0010: mul 
   L_0011: ret 
}

El código generado es idéntico, excepto para diferentes maxstack y la instrucción NOP adicional en el método F #.

Probablemente esto no sea significativo, pero tengo curiosidad por saber por qué el compilador F # insertaría NOP en una versión de lanzamiento.

¿Alguien puede explicar por qué?

(Estoy perfectamente consciente de que el compilador de F # no ha pasado por el mismo nivel de prueba del mundo real que el compilador de C #, pero esto es tan obvio que podría haberlo detectado).

EDITAR: el comando de compilación es el siguiente

C:\Program Files\Microsoft F#\v4.0\fsc.exe -o:obj\Release\FSharpLib.dll 
--debug:pdbonly --noframework --define:TRACE --optimize+ 
--target:library --warn:3 --warnaserror:76 --vserrors --utf8output --fullpaths 
--flaterrors "C:\Temp\.NETFramework,Version=v4.0.AssemblyAttributes.fs" Module1.fs 

(ensamblados referenciados eliminados por brevedad).

¿Fue útil?

Solución

La diferencia de maxstack se debe al hecho de que el compilador de C # compila el primer método con un encabezado del cuerpo del método «light», que se usa cuando el código es pequeño, no tiene excepciones y no tiene locales. En ese caso, el maxstack no se especifica y el valor predeterminado es 8.

El compilador F # está utilizando un encabezado del cuerpo del método «fat», y especifica el maxstack que ha calculado.

En cuanto al nop, es porque estás compilando en modo de depuración. Siempre comienzan un cuerpo de método con un nop. Ver en fsharp / ilxgen.ml:

// Add a nop to make way for the first sequence point. There is always such a 
// sequence point even when zapFirstSeqPointToStart=false
do if mgbuf.cenv.generateDebugSymbols  then codebuf.Add(i_nop);

Si compilo su factorial sin símbolos de depuración, no obtengo un nop.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top