Domanda

Sto giocando con F # in VS2010 beta2 e da quando sono nuovo in F #, ho appena scelto uno degli esempi comuni e sono andato avanti e ho implementato una funzione fattoriale come:

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

Se creo questo e guardo il codice generato in Reflector, ottengo il codice C # corrispondente:

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

      return n * Factorial(n - 1);
}

Quindi, se compilo la rappresentazione C # di Reflector del codice F #, mi aspetterei di ottenere IL identico.

Tuttavia, se compilo entrambi questi frammenti in modalità di rilascio e confronto l'IL generato, sono diversi (sono funzionalmente identici, ma differiscono ancora un po ').

L'implementazione di C # viene compilata in:

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

L'implementazione di F # viene compilata in:

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

Il codice generato è identico ad eccezione del maxstack diverso e dell'istruzione NOP aggiuntiva nel metodo F #.

Questo probabilmente non è significativo, ma sono curioso di sapere perché il compilatore F # inserisca NOP in una build di rilascio.

Qualcuno può spiegare perché?

(Sono perfettamente consapevole che il compilatore F # non ha attraversato lo stesso livello di test del mondo reale del compilatore C #, ma questo è così ovvio che immagino che sarebbe stato catturato).

EDIT: il comando di compilazione è il seguente

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 

(assemblee referenziate rimosse per brevità).

È stato utile?

Soluzione

La differenza del maxstack è dovuta al fatto che il compilatore C # compila il primo metodo con un'intestazione del corpo del metodo «leggero», che viene utilizzata ogni volta che il codice è piccolo, non ha eccezioni né locali. In tal caso, il maxstack non è specificato e il valore predefinito è 8.

Il compilatore F # sta usando un'intestazione del corpo del metodo «fat» e specifica il maxstack che ha calcolato.

Per quanto riguarda il nop, è perché stai compilando in modalità debug. Iniziano sempre un metodo con un nop. Vedi da 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);

Se compilo il tuo fattoriale senza simboli di debug, non ottengo un nop.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top