F#代码发布版本中的NOP

F#代码发布版本中的NOP,f#,visual-studio-2010,cil,F#,Visual Studio 2010,Cil,我在VS2010 beta2中使用F#,由于我是F#的新手,我只选择了一个常见的示例,并继续实现了一个阶乘函数,如下所示: let rec factorial n = if n <= 1 then 1 else n * factorial (n - 1);; F#实现编译为: .method public hidebysig static int32 Factorial(int32 n) cil managed { .maxstack 8 L_0000: ldarg.0

我在VS2010 beta2中使用F#,由于我是F#的新手,我只选择了一个常见的示例,并继续实现了一个阶乘函数,如下所示:

let rec factorial n =
  if n <= 1 then 1 else n * factorial (n - 1);;
F#实现编译为:

.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 
}
.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的差异是由于C#编译器使用«light»方法体头编译第一个方法,该方法在代码很小、没有异常和局部变量时使用。在这种情况下,不指定maxstack,默认为8

F#编译器正在使用«fat»方法主体标头,并指定它已计算的maxstack

至于nop,这是因为您是在调试模式下编译的。他们总是以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。

好吧,我在VS2010中使用默认的“release”构建配置文件,所以我假设我实际上是在发布模式下构建的。输出窗口显示“构建已启动:项目:FSharpLib,配置:释放任何CPU”。如果我改为“debug”,我会得到与预期完全不同的MSIL。我正在使用F#1.9.7.8和命令行进行测试。如果我没有通过/调试,我就不会得到nop。我用编译的命令行更新了问题,并尝试直接使用fsc.exe进行编译。同样的结果。根据输出窗口,VS2010b2没有与最新的编译器一起提供,因为它报告了F#version 1.9.7.4的版本号。这可能是区别吗?您发布的命令行包含
--debug:pdbonly
,这会触发nop的包含。nop IL指令是否与nop机器代码指令同步,或者它是否为真正的no op并被忽略?
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 
// 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);