Frage

I mit F # in VS2010 Beta2 spiele, und da ich zu F # neu bin, nahm ich nur eine der häufigsten Beispiele und ging voran und implementierte eine Fakultätsfunktion wie:

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

Wenn ich das bauen und auf dem generierten Code in Reflector suchen, bekomme ich den entsprechenden C # -Code:

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

      return n * Factorial(n - 1);
}

Wenn ich also Reflektor C # Darstellung des F # Code zu kompilieren, würde ich erwarten, identisch, IL zu erhalten.

Allerdings, wenn ich diese beiden Schnipsel im Release-Modus kompilieren und die erzeugte IL vergleichen, sie sind unterschiedlich (sie funktional identisch sind, unterscheidet sich aber noch ein wenig).

Die C # -Implementierung kompiliert:

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

Die F # Implementierung kompiliert:

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

Der generierte Code ist identisch mit Ausnahme von verschiedenen maxstack und der zusätzlichen NOP-Befehl in der F # Methode.

Dies ist wahrscheinlich nicht signifikant, aber ich bin neugierig, warum der F # -Compiler NOP in einem Release-Build einfügen würde.

Kann mir jemand erklären, warum?

(Ich weiß wohl, dass der F # -Compiler nicht durch das gleiche Niveau der realen Welt Tests als C # Compiler gegangen ist, aber das ist so offensichtlich, dass ich Bild würde es gefangen wurde).

EDIT: Die Kompilierung Befehl lautet wie folgt

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 

(referenzierten Assemblys der Kürze entfernt).

War es hilfreich?

Lösung

Der maxstack Unterschied auf die Tatsache zurückzuführen ist, dass der C # -Compiler die erste Methode mit einem «Licht» Methode Körper Header kompiliert, das verwendet wird, wenn der Code ist klein, hat keine Ausnahmen und keine Einheimischen. In diesem Fall wird die maxstack nicht angegeben und standardmäßig auf 8.

Der F # -Compiler wird mit einem «Fett» Methode Körper-Header und gibt den maxstack es berechnet hat.

Wie für die nop, es ist, weil Sie im Debug-Modus sind kompilieren. Sie beginnen immer ein Verfahren Körper mit einem nop. Siehe von 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);

Wenn ich Ihre faktorielles ohne Debug-Symbole zu kompilieren, ich habe nicht einen nop.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top