2009-05-18 5 views
5

누군가 MSIL의 몇 줄을 설명 할 수 있습니까? 평가 스택에서 값을 로컬 변수로 이동시키는 이유는 무엇입니까?누군가 MSIL의 몇 줄을 설명 할 수 있습니까?

다음 MSIL 코드는 단일 인수 (문자열)를로드하고 bool을 반환하는 메서드를 호출 한 다음 해당 bool 값을 반환합니다. 왜 이해가 안되는 이유는 메소드의 반환 값을 로컬 변수에 저장하기 위해 stloc.0을 호출 한 다음 매우 다음 레이블이있는 행 (명시하지 않은 것)으로 명시적인 무조건 제어 전송을 수행하고 값을 다시 반환하기 전에 평가 스택.

.maxstack 1 
.locals init ([0] bool CS$1$0000) 
L_0000: nop 
L_0001: ldarg.0 
L_0002: call bool FuncNameNotImporant::MethodNameNotImporant(string) 
L_0007: stloc.0 
L_0008: br.s L_000a 
L_000a: ldloc.0 
L_000b: ret 

는이 계산 스택에 값을 보장하기 위해 유형 검사의 일종을 수행하는 것입니다 않는 이유에 내 추측은 실제로 그것을 반환하기 전에 부울 값입니다. 그러나 저는 다음 줄로의 명백한 점프에 관해서는 단서가 없습니다. 어쨌든 거기에 가지 않을 래? 메서드의 C# 소스 코드는 메서드의 결과를 반환하는 한 줄입니다.

답변

7

:

설정할 수있는 3 개 브레이크 포인트가 있습니다
bool foo(string arg) 
{ 
    return bar(arg); 
} 

: 함수의 여는 중괄호에서

  1. 가.
  2. "return"행.
  3. 함수의 닫는 중괄호에.

여는 중괄호의 중단 점 설정은 "이 함수가 호출 될 때 중단"을 의미합니다. 그래서 메서드의 시작 부분에 no-op 명령이 있습니다. 중단 점이 여는 중괄호에 설정되면 디버거는 실제로 아무 작업도하지 않고 설정합니다.

닫는 중괄호에 중단 점을 설정하는 것은 "이 함수가 종료 될 때 중단"을 의미합니다. 이를 위해 브레이크 포인트가 설정 될 수있는 IL에서 함수가 단일 리턴 명령을 가져야합니다. 컴파일러 가능하게하는 방법의 아래쪽에 다음 코드를 반환 값을 저장하는 임시 변수를 사용하고

$retTmp = retVal; 
goto exit; 

return retVal; 

변환 후 주입 :

exit: 
return $ret; 

또한 디버그 모드에서 컴파일러는 생성 된 코드에 대해 어리 석습니다.그들은 기본적으로 같은 것을 할 : 귀하의 경우

GenerateProlog(); 
foreach (var statement in statements) 
{ 
    Generate(statement); 
} 
GenerateEpilog(); 

을, 당신은보고있다 :

return foo(arg); 

가로 번역되는 : 컴파일러는 "슬라이딩 윈도우 최적화"를 수행 한 경우

; //this is a no-op 
bool retTemp = false; 
retTemp = foo(arg); 
goto exit; 
exit: 
return retTemp; 

그 코드를보고 약간의 중복성이 있음을 깨달을 수도 있습니다. 그러나 컴파일러는 일반적으로 디버그 모드에서 그렇게하지 않습니다. 컴파일러 최적화는 변수 제거 및 명령어 순서 변경과 같은 작업을 수행 할 수 있으므로 디버깅이 어려워집니다. 디버그 빌드의 목적은 디버깅을 가능하게하기위한 것이므로 최적화를 켜는 것은 좋지 않습니다.

릴리스 빌드에서 코드는 그렇게 보이지 않습니다.

return bar(arg); 

아주 간단 찾고 끝 : 컴파일러는 단지 다음과 잎 개폐 괄호에 브레이크 포인트를 가능하게하는 특별한 코드를 컴파일 할을 소개하지 않기 때문이다.

그러나 주목할 점은 C# 컴파일러가 소매업 빌드에서도 많은 슬라이딩 윈도우 최적화를 수행한다고 생각하지 않는다는 것입니다. 대부분의 최적화 작업은 기본 프로세서 아키텍처에 따라 다르므로 JIT 컴파일러가 수행합니다. C# 컴파일러에서 최적화를 수행하면 C# 컴파일러에서 프로세서 최적화에 영향을 줄 수 있으므로 코드를 최적화하는 JIT의 기능을 방해 할 수 있습니다. 최적화되지 않은 코드 생성으로 생성되는 패턴을 찾고 최적화 된 IL을 보면 혼란 스러움). 그래서 보통 manged 코드 컴파일러는 그것을하지 않습니다. 데드 코드 감지 및 라이브 변수 분석과 같은 일부 "비싼 작업"(JIT는 런타임에 수행하기를 원하지 않음)을 수행하지만 슬라이딩 윈도우 최적화로 해결 된 문제는 해결하지 못합니다.

4

디버그 모드 또는 릴리스 모드로 컴파일 중이십니까? 릴리스 모드에서 나는 다음을 얻습니다.

.method private hidebysig static bool Test1(string arg) cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.0 
    L_0001: call bool FuncNameNotImportant::MethodNameNotImportant(string) 
    L_0006: ret 
} 

표시되는 분기는 디버거를 지원하기위한 것입니다. 당신이 디버그 모드에서 컴파일 된 코드로, 디버거에서이 기능을 열면

+0

나에게 합리적인 소리 –

관련 문제