컴파일러에 의해 생성 된 일부 자동 코드 인 “호출 사이트”입니다.이 용어를 자주 접하고 호출 메서드를 단순히 “호출 사이트”라고하는 것처럼 들립니다. -말 그대로 괜찮아 보이지만 좀 더 복잡하다고 생각합니다. 그리고 “호출 사이트”가 컴파일러 생성 코드 인 경우-어떤 상황에서 이것이 필요합니까?
C # .Net의 맥락에서 이야기하고 있지만 이것은 표준 용어로 보입니다. 몇 가지 예를 통해 명확하고 정확한 설명을 주시면 감사하겠습니다.
댓글
- 소스 코드와 자동에서 호출 사이트 개념이 있습니다. -생성 된 개체 코드.
- C # 4 이상에서 동적 작업을 위해 호출 사이트가 생성되는 방식을 살펴볼 수 있습니다. 매우 흥미 롭습니다.
- @EricLippert 감사합니다. 다행스럽게도 링크 를 찾았습니다. 여기서 매우 아름답게 설명하셨습니다. 그러나 통화 사이트 생성에 대해 구체적으로 설명하는 블로그를 찾을 수 없습니다.
답변
“전화 사이트 ”는 함수 또는 메서드가 호출되는 위치를 나타냅니다. 컴파일러 구성의 일반적인 용어이며 C #에만 국한되지 않습니다.
foo(); // call site void foo() { ... } // function definition
호출 사이트는 특수 생성 된 코드가 아닙니다. 그러나 호출 사이트에서 컴파일러는 함수를 호출하는 명령을 내 보냅니다. 일반적으로 다음과 같습니다.
- 현재 컨텍스트를 스택 프레임에 저장합니다.
- 대상 함수의 호출 규칙에 따라 모든 인수를 저장합니다.
- 메소드 디스패치가 필요할 수있는 대상 함수를 호출합니다.
- 호출 규칙에 따라 반환 값을 검색합니다.
- 스택 프레임에서 컨텍스트를 복원합니다.
메소드 디스패치는 실제로 호출해야하는 함수를 찾기 위해 복잡한 코드를 실행해야 할 수 있습니다. 이는 virtual
메서드, 특히 인터페이스를 통해 메서드를 호출 할 때 필요합니다. 완전한 메소드 디스패치 절차는 비용이 많이들 수 있습니다 (구현 된 인터페이스 수에서 O (n) 또는 사용 가능한 메소드 수에서 O (n)). 그러나 대부분 (일반적으로 70–90 %) 호출 사이트에는 동일한 유형의 개체가 표시됩니다. 그런 다음 메서드 조회 결과를 캐시하는 것이 좋습니다. 그런 다음 컴파일러는 호출 사이트에서 다음과 같은 코드를 생성 할 수 있습니다.
static lastType = null; static lastMethod = null; if (type(instance) != lastType) { lastType = type(instance); lastMethod = performMethodLookup(instance, methodName); } result = lastMethod(instance, args);
이를 모노 모픽 라고합니다. 인라인 캐시 . .NET CLR은 Virtual Stub Dispatch 라는 약간 더 복잡한 접근 방식을 개발했습니다. 호출 사이트에서 디스패치를 수행하는 대신 런타임 JIT는 스텁 메서드를 컴파일합니다. 전체 메소드 디스패치 프로 시저를 수행하고 캐시 된 메소드를 사용하기위한 다른 스텁이 있습니다. 호출 사이트에서는 스텁에 대한 호출 만 있고 스텁은 호출을 실제 대상으로 전달합니다. 이 호출 사이트의 통계에 따라 호출 사이트의 기계어 코드가 다른 스텁을 사용하도록 패치됩니다.
Answer
호출 사이트의 가장 일반적인 용도는 아마도 현재 Wikipedia에 선언 된 일 것입니다. 이것은 일부 코드에서 함수 또는 서브 루틴이 만들어집니다. 모든 언어에 적용 할 수있는 완전히 일반적인 용어입니다 (동적 프로그래밍과는 전혀 관련이 없습니다!).
저는 일반적으로 사용되는 용어를 듣습니다 (단지 용어 “호출”) 호출의 기본 의미론 또는 함수 / 메소드 정의의 의미와는 반대로 함수 / 메서드 / 서브 루틴이 호출되는 코드의 구문과 의미를 논의하고 있음을 명확히합니다. 이런 식으로 컴파일러 나 생성 코드에 대해서는 절대 아닙니다 (아몬이 이미 논의했듯이 컴파일러 / 런타임에 의해 생성 된 코드에이 용어가 여전히 적용 되더라도). 호출로 해석되는 특정 코드를 컨텍스트로 가져오고 때로는 바로 근처에있는 코드를 가져 오는 것에 대해 설명합니다.
이것이 제가 머릿속에있는 일종의 그림입니다.
call-site call call-target/method definition --> --> int.TryParse(str, out i); (runtime) public static bool TryPars(...
“call-site “는 호출 구문과 호출자에게 영향을 미치는 의미 (amon에 의해 자세히 설명 됨)에 대해 이야기 할 때 유용한 용어입니다. 예를 들어 C #의 새로운 in
수정 자, “in”으로 인수를 전달하는 “호출”은 이와 관련된 특정 의미를 가지고 있습니다 (참고로 전달됩니다. 사본), 그러나 “”호출 사이트에서 “구문에서 반드시 명확하지는 않습니다. 여기서 in
는 필수가 아닙니다. 아이디어는 in
를 사용하여 참조로 인수를 전달하는 호출 사이트 의미 (즉, 호출자 / 호출 사이트에 영향을주는 동작)가 가깝다는 것입니다. 호출 사이트에서 구문으로 명확화 할 필요가없는 값으로 전달하는 것만 큼 충분합니다.나는이 주장에 동의하지 않습니다. “call-site”와 같은 용어없이 논의하기가 어려울 것입니다!
또 다른 예 : 동적 호출 (예 : 가상 / 인터페이스 방법)은 다소 복잡한 런타임 동작 (다시 말하지만, amon에 의해 자세히 설명 됨) 및 “컴파일시 어떤 메서드가 호출 될지 알 수 없지만”호출 사이트 “가 신경 쓰는 모든 것은 해당 호출을 디스패치하는 의미입니다.
object
의 경우 실제로 string
정말 신경 쓰지 않습니다.
호출 사이트에서, object
가 가상 ToString()
메소드를 노출하는 것만 신경 쓰게됩니다 (런타임까지 실제로 호출 할 메서드를 결정합니다). 실제로 호출 사이트 (예 : C #)에서 이것이 가상 호출인지 여부가 구문에서 반드시 명확하지는 않습니다. 가상 호출과 가상 호출이 아닌 호출 사이의 구분은 호출시 충분히 중요하지 않은 것으로 간주됩니다. (컴파일러 / 런타임이 의미있는 호출을하는 것이 매우 중요하더라도) 호출 사이트 에서 프로그래머를 위해 명확화 할 필요가없는 사이트 >
마지막 예 : C # “s ref
및 C ++”s &
: 둘 다 호출 사이트의 의미 체계 언어는 두 언어에서 거의 동일합니다. 값이 아닌 참조가 전달되지만 각 언어는 호출 사이트에서 다른 구문을 가지고 있습니다. 여기서 C #은 ref
를 요구하고 C ++는 그렇지 않습니다. &
(또는 이와 유사한 것)이 필요합니다. 다시 말하지만, 언어 설계자는 호출 사이트의 의미 체계에 의해 정보를 받아 호출 사이트에서 호출이 표현되는 방식에 대한 몇 가지 구문 결정을 내 렸습니다. (저는 호출 사이트 의미를 노출하기 때문에 C # 호출 사이트 구문을 선호하는데, 프로그래머로서 제가 그러한 호출을 할 때 인정해야한다고 생각합니다). 메소드 정의는 매개 변수를 수정하는 동작을 변경하기 때문에 참조로 매개 변수를 수신하고 있음을 알아야한다는 사실이 분명합니다 (예 : =
사용). 그러나 런타임이 신경 쓰지 않는다 (런타임 디스패치가 명목상 정보를받는 정적으로 형식화 된 언어에서) : 호출자로부터 피 호출자에게이 값을 가져 오면됩니다. , 참조인지 아닌지 상관하지 않습니다. 이는 호출 사이트 및 호출 대상에 대한 문제입니다.
좀 더 느슨하게 “호출 사이트”는 호출을 나타내는 코드와 그 주변의 “관련”코드 (단지 “호출”이 아님). 예를 들어 C #에서 호출 사이트 “에”더미 변수를 정의하는 것을 참조 할 수 있습니다. TryParse
메서드를 호출하는 경우 :
int dummy; bool looksLikeAnInt = int.TryParse(str, out dummy);
이 전체 “블록”은 호출 사이트의 일부로 간주 될 수 있습니다. 나는 이것이 덜 “정확한”의미라고 생각하지만 그것이 사용을 멈추게하지 않습니다.