Загружаем каталог…
Загружаем каталог…
인터프리터는 명령을 실행할 때마다 다음에 무엇을 처리할지 선택합니다. 덧셈처럼 명령 자체가 단순하면 이 디스패치 비용도 설계에서 따져 볼 문제가 됩니다. Jimmy Ostler는 자신의 ternary 프로젝트를 개선하려는 탐색 중 Scala의 VM 디스패치 비교에 착안해 Rust 구현을 실험했으며, 그 과정을 2026년 8월 1일 「Tail-Call Interpreters in Rust」 에 공개했습니다. 이 실험을 읽을 때 중심에 둘 질문은 다음 명령으로 넘어가는 흐름을 Rust에서 어떻게 표현하고 보장하느냐입니다. 꼬리 호출은 돌아올 일을 남기지 않습니다 꼬리 호출 최적화는 함수의 마지막 호출을 점프로 처리해 호출 프레임이 계속 쌓이지 않도록 합니다. 다른 함수를 호출한 뒤 그 결과를 그대로 반환한다면, 호출한 쪽으로 돌아와 추가로 수행할 작업이 없습니다. 따라서 코드가 재귀 형태라는 이유만으로 실행 중 호출 스택도 계속 늘어난다고 판단해서는 안 됩니다. Ostler의 설명에 따르면 Rust는 높은 최적화 수준에서 이런 변환을 수행할 수 있습니다. 실험에 사용한 explicit_tail_calls 는 컴파일러의 선택에 맡기던 변환을 명시적으로 요구하는 불안정 기능입니다. 예제의 become 은 해당 호출을 꼬리 호출로 처리하거나 오류를 내도록 요구합니다. 안정판 Rust에서 그대로 사용할 수 있는 구문으로 받아들여서는 안 됩니다. 여기서 재사용하는 호출 프레임과 계산 값을 보관하는 값 스택은 별개입니다. 명령 전환 때 호출 프레임이 누적되지 않아도, 실행하는 프로그램이 값을 계속 넣으면 값 스택의 공간은 소진됩니다. 꼬리 호출이 보장하는 범위는 호출 흐름이며, 값 저장 공간의 관리는 머신 설계에 남습니다. 명령 실행은 상태를 넘기는 과정입니다 예제의 dispatch 는 명령 하나를 처리한 뒤 갱신한 스택 포인터와 명령 포인터를 다음 호출에 전달합니다. 명령 집합은 Lit , Add , Sub , Mul , Div 로 구성됩니다. Lit 는 값을 스택에 추가하고, 나머지는 산술 연산을 수행합니다. 산술 명령 안에서 값이 이동하는 순서는 다음과 같습니다. 실행 상태를 담는 sp 는 값 스택의 위치를, ip 는 실행할 명령의 위치를 나타냅니다. 값을 추가한 분기는 sp + 1 과 ip + 1 을 전달합니다. 산술 분기는 두 피연산자가 결과 하나로 바뀌므로 sp - 1 과 ip + 1 을 전달합니다. 각 분기 끝의 become dispatch(...) 에 이 상태 변화가 드러납니다. 종료 조건은 명령 포인터가 명령 배열의 길이에 도달하는 것입니다. 이때는 다음 명령으로 이동하지 않고 값 스택의 마지막 값을 반환합니다. 코드를 읽을 때는 각 연산의 계산식뿐 아니라 분기가 넘기는 포인터와 종료 시 사용하는 위치를 함께 보면 실행 상태를 따라갈 수 있습니다. 꼬리 호출 뒤에도 명령 선택은 남습니다 예제는 자기 자신을 꼬리 호출하면서도 하나의 match 에서 명령 종류를 고르는 switch dispatch 구조를 유지합니다. 일반적인 switch dispatch 설명에는 반복문이 등장하지만, Ostler가 제시한 비교 기준 코드는 재귀 호출로 실행을 이어 갑니다. 명령을 어디서 선택하는지와 다음 실행을 어떤 구문으로 표현하는지는 서로 다른 설계 요소입니다. become 을 사용했다는 사실이 중앙의 명령 판별까지 제거하지는 않습니다. 글에서 이어서 소개하는 subroutine dispatch는 명령 선택 구조를 바꾸려는 시도입니다. 이 비교에서 꼬리 호출 여부만 보면 명령을 선택하는 방식의 차이를 놓칩니다. 실제 처리 시간에는 명령 선택 외에도 상태 접근과 산술 연산이 함께 반영되므로, 디스패치 구조를 비교할 때는 실행에 포함되는 작업을 함께 봐야 합니다. 실험 코드에는 입력 전제가 있습니다 이 예제를 제품 코드로 옮기려면 전역 상태의 소유권과 명령열의 유효성을 별도로 설계해야 합니다. 예제는 크기 32의 값 스택과 전역 명령 배열을 사용하며, 구현에는 static mut 와 unsafe 가 들어갑니다. Ostler는 Scala 구현과 형태를 맞추기 위한 선택이었다고 설명하면서 이런 Rust 작성 방식을 권장하지 않는다고 밝힙니다. 비교 대상과 코드 형태를 맞추려는 목적이 상태 관리 방식에 반영된 것입니다. 실제 구현을 위한 설계 제안으로는 VM 인스턴스가 값 스택과 명령 배열을 소유하도록 구성하는 방향이 있습니다. 소유 구조를 바꾼 뒤에도 명시적 꼬리 호출을 적용할 수 있는지는 다시 점검해야 합니다. 배열 접근에는 필요한 값이 이미 존재한다는 전제도 있습니다. 산술 명령은 sp - 2 와 sp - 1 을 읽고, 실행이 끝나면 sp - 1 을 반환합니다. 따라서 빈 프로그램, 피연산자가 부족한 명령열, 값 스택의 용량을 초과하는 입력을 어떻게 처리할지 정해야 합니다. 이 입력 조건은 재귀 호출을 어떤 방식으로 실행하는지와 독립된 책임입니다. 성능 비교에는 같은 실행 기준이 필요합니다 속도를 비교하려면 동일한 명령열에서 동일한 계산 결과를 얻는 구현을 대상으로 측정해야 합니다. 소개된 subroutine dispatch 설명은 구현 도중에 끝나며, 완성된 구현과 벤치마크 수치가 함께 제시되지 않아 두 방식의 속도 우열은 정해져 있지 않습니다. 따라서 코드의 형태를 보고 어느 쪽이 더 빠른지 결론 내리기보다, 비교할 실행 조건부터 맞추는 것이 이 글의 제안입니다. 직접 비교하는 경우에는 컴파일러와 최적화 설정도 기록하는 편이 좋습니다. Rust가 최적화 수준에 따라 꼬리 호출 변환을 수행할 수 있다는 설명을 고려하면, 어떤 설정에서 실행했는지는 결과를 해석하는 데 필요한 조건입니다. 계산 결과가 같은지 살피는 일도 명령 전환 구조를 바꾸면서 머신의 동작을 유지했는지 판단하는 기준이 됩니다. 또한 이 실험의 대상은 단순한 스택 머신입니다. Ostler는 더 복잡한 레지스터 머신을 구분해 다루겠다고 밝혔습니다. 스택 머신에서 얻은 측정 결과를 다른 구조에 적용하려면 그 구조에서의 검증이 별도로 필요합니다. 어떤 경우에 검토할 만한가 꼬리 호출 방식은 다음 명령으로 넘길 상태와 제어 흐름을 실험하려는 인터프리터 구현에 검토할 만합니다. 단순한 머신을 통해 명령 실행과 다음 호출의 연결을 이해하려는 경우에도 구체적인 출발점이 됩니다. 반면 비교 실험의 코드를 곧바로 제품 구현의 틀로 선택하는 것은 맞지 않습니다. 작성자가 설명한 코드 형태의 목적을 고려하면, 제품 적용에서는 디스패치 구문을 고르는 일과 실행 상태를 관리하는 일을 함께 설계하는 편이 타당합니다. 마무리 이 실험을 적용할 때는 다음 실행에 필요한 상태와 그 소유자를 먼저 정하고, 컴파일러에 요구할 호출 특성을 명확히 하는 것이 우선입니다. 호출 스택의 누적을 막는 설계를 마련한 뒤, 속도 개선 여부는 실제로 실행할 명령열에서 측정해 판단해야 합니다. 원문: webi 기술 블로그 참고한 자료: Tail-Call Interpreters in Rust – Jimmy Ostler Jeeves - 판단 전에 추론하는 Jev 방식의 의사결정 모델 Claude 일부 서비스 장애
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
Rust 꼬리 호출 인터프리터는 실행 흐름을 어떻게 바꾸나. 인터프리터는 명령을 실행할 때마다 다음에 무엇을 처리할지 선택합니다. 덧셈처럼 명령 자체가 단순하면 이 디스패치 비용도 설계에서 따져 볼 문제가 됩니다. Jimmy Ostler는 자신의 ternary 프로젝트를 개선하려는 탐색 중 Scala의 VM 디스패치 비교에 착안해 Rust 구현을 실험했으며, 그 과정을 2026년 8월 1일 「Tail-Call Interpreters in Rust」 에 공개했습니다. 이 실험을 읽을 때 중심에 둘 질문은 다음 명령으로 넘어가는 흐름을 Rust에서 어떻게 표현하고 보장하느냐입니다. 꼬리 호출은 돌아올 일을 남기지 않습니다 꼬리 호출 최적화는 함수의 마지막 호출을 점프로 처리해 호출 프레임이 계속 쌓이지 않도록…
Открыть источник