2009-10-23 16 views
6

gram z F # w VS2010 beta2, a ponieważ jestem nowy F #, po prostu wybrał jeden z typowych przykładów i poszedł do przodu i wdrożył funkcję silni jak:NOP w wersji kompilacji F # Kod

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

Jeśli buduję ten i patrzeć na wygenerowanego kodu w reflektor, pojawia się odpowiedni kod C#:

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

     return n * Factorial(n - 1); 
} 

Więc jeśli mogę skompilować reflektor w C# reprezentację kod F #, chciałbym oczekiwać, aby uzyskać identyczną IL.

Jednakże, jeśli skompiluję oba te fragmenty w trybie zwolnienia i porównam wygenerowaną IL, są one różne (są funkcjonalnie identyczne, ale wciąż nieco różnią się).

C realizacja # kompiluje do:

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

the # wdrożenie F kompiluje do:

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

Wygenerowany kod jest identyczny z wyjątkiem innego maxstack oraz dodatkowych instrukcji NOP w # metody F.

To prawdopodobnie nie jest znaczące, ale jestem ciekawy, dlaczego kompilator F # wstawił NOP w kompilacji wydania.

Czy ktoś może wyjaśnić, dlaczego?

(Jestem w pełni świadomy, że kompilator F # nie przeszedł tego samego poziomu testów w świecie rzeczywistym, co kompilator języka C#, ale jest to tak oczywiste, że obraz zostałby przechwycony).

Edycja: Polecenie kompilacji następująco

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 

(zespoły użyte usunięte dla uproszczenia).

Odpowiedz

17

Różnica maksymalnych wartości szczytowych wynika z faktu, że kompilator C# kompiluje pierwszą metodę za pomocą nagłówka treści metody "lekkiej", używanej zawsze, gdy kod jest mały, nie ma żadnych wyjątków ani lokalnych. W takim przypadku wartość maxstack nie jest określona, ​​a wartość domyślna to 8.

Kompilator F # używa nagłówka treści metody "gruby" i określa obliczony maksymalny rozmiar.

Co do nop, to dlatego, że kompilujesz w trybie debugowania. Zawsze uruchamiają ciało metody z nopem. See 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); 

Gdybym skompilować silni bez symboli debugowania, nie dostać NOP.

+0

Cóż, używam domyślnego profilu kompilacji "release" w VS2010, więc zakładam, że faktycznie buduję w trybie zwolnienia. Okno wyjściowe mówi "Rozpoczęto kompilację: Projekt: FSharpLib, Konfiguracja: Zwolnij dowolny procesor". Jeśli zmienię na "debugowanie", otrzymuję zupełnie inny MSIL zgodnie z oczekiwaniami. –

+0

Testuję używając F # 1.9.7.8 i wiersza poleceń. Jeśli nie przekażę/debuguję, nie dostanę nop. –

+0

Zaktualizowałem pytanie za pomocą wiersza poleceń do kompilacji i próbowałem skompilować bezpośrednio za pomocą fsc.exe. Ten sam wynik. Według okna wyjściowego VS2010b2 nie jest dostarczany z najnowszym kompilatorem, ponieważ zgłasza numer wersji F # w wersji 1.9.7.4. Czy to może być różnica? –

Powiązane problemy