Question

Je joue avec F # dans VS2010 beta2 et comme je suis novice en F #, je viens de choisir l'un des exemples courants et de mettre en œuvre une fonction factorielle comme suit:

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

Si je construis cela et que je regarde le code généré dans Reflector, je reçois le code C # correspondant:

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

      return n * Factorial(n - 1);
}

Donc, si je compile la représentation C # du code F # par Reflector, je m'attendrais à obtenir un IL identique.

Cependant, si je compile ces deux extraits en mode édition et que je compare l'IL généré, ils sont différents (ils sont fonctionnellement identiques, mais diffèrent encore un peu).

L’implémentation C # est compilée pour:

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

L’implémentation de F # est compilée pour:

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

Le code généré est identique à l'exception de maxstack différent et de l'instruction NOP supplémentaire dans la méthode F #.

Ceci n’est probablement pas significatif, mais je suis curieux de savoir pourquoi le compilateur F # insérerait NOP dans une version release.

Quelqu'un peut-il expliquer pourquoi?

(Je suis parfaitement conscient du fait que le compilateur F # n'a pas passé le même niveau de test que le compilateur C # dans le monde réel, mais c'est tellement évident que j'imagine qu'il aurait été attrapé).

EDIT: la commande de compilation est la suivante

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 

(assemblages référencés supprimés par souci de concision).

Était-ce utile?

La solution

La différence entre maxstack est due au fait que le compilateur C # compile la première méthode avec un paramètre & # 171; light & # 187; l'en-tête du corps de la méthode, qui est utilisé chaque fois que le code est petit, n'a pas d'exception ni d'emplacement Dans ce cas, la pile max n'est pas spécifiée et la valeur par défaut est 8.

Le compilateur F # utilise une & # 171; graisse & # 187; en-tête du corps de la méthode et spécifie le maxstack qu’il a calculé.

Quant au nop, c’est parce que vous compilez en mode débogage. Ils commencent toujours un corps de méthode avec un nop. Voir dans 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);

Si je compile votre factorielle sans symboles de débogage, je ne reçois pas de nop.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top