2009-10-23 18 views
6

estoy jugando con F # en beta2 VS2010, y como yo soy nuevo en F #, que acaba de recoger uno de los ejemplos más comunes y siguió adelante e implementó una función factorial como:NOP en la liberación de la acumulación de F # Código

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

Si construyo esto y miro el código generado en el reflector, consigo el correspondiente código C#:

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

     return n * Factorial(n - 1); 
} 

Así que si puedo compilar C# representación del reflector del # código F, I sería de esperar para obtener idéntica IL.

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 difieren un poco).

El C# aplicación compila a:

.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 
} 

El F # aplicación compila a:

.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 a excepción de diferente maxstack y la instrucción NOP adicional en el método F #.

Esto probablemente no sea significativo, pero tengo curiosidad de por qué el compilador F # insertaría NOP en una compilación de lanzamiento.

¿Alguien puede explicar por qué?

(Estoy perfectamente enterado de que el compilador F # no ha pasado por el mismo nivel de pruebas del mundo real que el compilador C#, pero esto es tan obvio que la imagen podría haberse capturado).

EDIT: El comando de compilación es como sigue

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 de referencia eliminan por razones de brevedad).

Respuesta

17

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

El compilador de F # está utilizando un encabezado de cuerpo de método «graso» y especifica la pila máxima que ha calculado.

En cuanto al nop, es porque está compilando en modo de depuración. Siempre comienzan un cuerpo de método con un nop. Ver desde 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 compilar su factorial sin símbolos de depuración, no consigo un nop.

+0

Bueno, utilizo el perfil de compilación predeterminado "versión" en VS2010, así que supongo que en realidad estoy construyendo en modo de lanzamiento. La ventana de salida dice "Build started: Project: FSharpLib, Configuration: Release Any CPU". Si cambio a "depurar" obtengo un MSIL completamente diferente como se esperaba. –

+0

Estoy probando usando F # 1.9.7.8 y la línea de comando. Si no paso/depuro, no recibo un nop. –

+0

Actualicé la pregunta con la línea de comando para la compilación e intenté compilar usando fsc.exe directamente. Mismo resultado. De acuerdo con la ventana de salida, VS2010b2 no incluye el compilador más reciente ya que informa un número de versión de F # Versión 1.9.7.4. ¿Podría ser esa la diferencia? –

Cuestiones relacionadas