Pergunta

Eu estou jogando com F # no VS2010 beta2, e desde que eu sou novo para F #, eu só peguei um dos exemplos comuns e fui em frente e implementou uma função fatorial como:

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

Se eu construir isso e olhar para o código gerado no refletor, eu obter o código C # correspondente:

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

      return n * Factorial(n - 1);
}

Então, se eu compilar representação do refletor C # do código F #, eu esperaria para obter IL idênticos.

No entanto, se eu compilar ambos estes fragmentos no modo de libertação e comparar a IL gerados, eles são diferentes (que são funcionalmente idênticos, mas difere ainda um pouco).

Os compila C # execução:

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

A F # implementação compila para:

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

O código gerado é idêntica, exceto para diferentes maxstack ea instrução NOP adicional no método F #.

Este é provavelmente não é significativo, mas estou curioso para saber por que o compilador F # iria inserir NOP em uma compilação de lançamento.

Alguém pode explicar por quê?

(Estou perfeitamente consciente de que o compilador F # não passou pelo mesmo nível de mundo real testando como o compilador C #, mas isso é tão óbvio que a imagem que eu teria sido capturado).

EDIT: O comando de compilação é a seguinte

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 

(conjuntos referenciados removido por brevidade).

Foi útil?

Solução

A diferença maxstack é devido ao fato de que o compilador C # compila o primeiro método com uma «luz» cabeçalho corpo do método, que é usado sempre que o código é pequeno, não tem exceções e não moradores. Nesse caso, o maxstack não for especificado e padrões para 8.

O compilador F # está usando um «gordura» cabeçalho corpo do método, e especifica o maxstack tem computado.

Quanto ao nop, é porque você está compilando no modo de depuração. Eles sempre começar um corpo de método com um nop. Veja a partir 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 eu compilar o fatorial, sem símbolos de depuração, eu não obter um nop.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top