문제

나는 VS2010 Beta2에서 F#을 가지고 놀고 있으며, F#에 익숙하지 않기 때문에 일반적인 예 중 하나를 선택하고 다음과 같은 요인 기능을 구현했습니다.

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

이것을 빌드하고 반사기에서 생성 된 코드를 보면 해당 C# 코드를 얻습니다.

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

      return n * Factorial(n - 1);
}

F# 코드의 반사기의 C# 표현을 컴파일하면 동일한 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# 컴파일러와 동일한 수준의 실제 테스트를 거치지 않았다는 것을 완벽하게 알고 있습니다. 그러나 이것은 이미 이미지가 잡혔을 것입니다).

편집 : 컴파일 명령은 다음과 같습니다

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 

(참조 된 어셈블리는 간결하게 제거되었습니다).

도움이 되었습니까?

해결책

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가 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top