2009-10-23 14 views
6

のリリースビルドでは、私はVS2010のベータ2でのF#で遊んでいます、と私はF#に新しいですから、私はちょうど一般的な例の一つを選んだし、先に行って、として、階乗関数を実装:NOPはF#コード

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

私はこれを構築し、リフレクターで生成されたコードを見ると、私は、対応するC#のコードを取得する:私はF#のコードのリフレクターのC#の表現をコンパイルする場合

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

     return n * Factorial(n - 1); 
} 

だから、私は同じILを得ることを期待します。

しかし、これらのスニペットをリリースモードでコンパイルし、生成されたILを比較すると、それらは異なっています(機能的には同じですが、まだ少し異なります)。

C#実装がにコンパイル:

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

F#実装はにコンパイル:

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

生成されたコード異なるmaxstackおよびF#の方法で追加のNOP命令を除いて同一です。

これはおそらく重要ではありませんが、なぜF#コンパイラがリリースビルドにNOPを挿入するのか不思議です。

誰でも理由を説明できますか?

(私は、F#コンパイラがC#コンパイラと同じレベルの実世界テストを行っていないことを完全に認識していますが、これは明らかです。

EDITは:(参照アセンブリは、簡潔にするために除去)

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 

を次のようにコンパイルコマンドです。

答えて

17

maxstackの相違点は、C#コンパイラが、コードが小さく、例外もローカルでもない場合に使用される«light»メソッド本体ヘッダーで最初のメソッドをコンパイルするためです。その場合、maxstackは指定されず、デフォルトは8になります。

F#コンパイラは、«fat»メソッドの本体ヘッダを使用して、計算したmaxstackを指定します。

nopに関しては、デバッグモードでコンパイルしているからです。彼らは常にノップでメソッド本体を開始します。 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); 

私はデバッグシンボルなしであなたの階乗をコンパイルする場合、私はNOPを得ることはありません。

+0

まあ、私はVS2010のデフォルトの "リリース"ビルドプロファイルを使用しているので、私は実際にリリースモードで構築していると思います。出力ウィンドウに「Build started:Project:FSharpLib、Configuration:Release CPU」と表示されます。私が "デバッグ"に変更した場合、私は全く異なるMSILを期待どおりに取得します。 –

+0

私はF#1.9.7.8とコマンドラインを使ってテストしています。私が合格/デバッグしなければ、私はノップを取得しないでください。 –

+0

私はコンパイルのコマンドラインで質問を更新し、fsc.exeを使って直接コンパイルしようとしました。同じ結果。出力ウィンドウによれば、VS2010b2はF#バージョン1.9.7.4のバージョン番号を報告するので、最新のコンパイラと共に出荷されません。違いがありますか? –

関連する問題