YARV to LLVM은 어떻게 실패했는가?

[29S03] How Did Yarv2llvm Fail (ja)

작성자
RubyKaigi
발행일
2025년 10월 05일

핵심 요약

  • 1 Ruby 1.9 VM의 네이티브 코드 변환 프로젝트인 YARV to LLVM은 동적 디스패치, 박싱/언박싱 오버헤드, 런타임 의존성, 복잡한 타입 추론, 유지보수 난이도, 그리고 `eval`, `BigNum`과 같은 '블랙 매직' 기능 미지원 등의 문제로 한계에 직면했습니다.
  • 2 YARV to LLVM의 문제점들을 해결하기 위해 새로운 트랜슬레이터 YTL이 개발 중이며, 이는 풀셋 Ruby 지원을 목표로 LLVM 대신 자체 네이티브 코드 생성 라이브러리(YTL JIT)를 구축하고 동적 재컴파일 방식을 채택합니다.
  • 3 YTL은 런타임을 Ruby로 작성하여 타입 추론 결과에 따른 특수화를 가능하게 하고, 코드 생성과 타입 추론을 분리하며, 타입 추론 자체를 네이티브 코드로 실행하여 성능 및 유지보수 문제를 개선하고자 합니다.

도입

본 발표는 Ruby 1.9 VM을 네이티브 코드로 변환하는 두 가지 트랜슬레이터, YARV to LLVM과 YTL에 대해 다룹니다. 고속 컴파일러를 구축하는 과정에서 발생하는 주요 문제점으로는 동적 메서드 디스패치와 박싱/언박싱 오버헤드가 지목됩니다. 이러한 문제들은 변수의 타입이 실행 시점에 결정되는 Ruby의 특성에서 기인하며, 타입 추론을 통해 부분적으로 해결될 수 있으나, 타입 추론만으로는 완전한 고속 처리를 달성하기 어렵다는 점이 강조됩니다.

YARV to LLVM의 소개 및 한계점

YARV to LLVM은 Ruby 1.9 VM(YARV)을 LLVM IR로 변환하고, LLVM의 최적화 기능과 네이티브 코드 변환을 활용합니다. Tom Bagby의 LLVM Ruby 라이브러리를 사용하며, 타입 추론 기능은 Ruby로 구현되어 성능 향상을 목표로 했습니다. 피보나치 계산에서 40배 가까운 속도 향상을 보여주었으며, SDL과 동적 컴파일된 헬로월드 프로그램 시연을 통해 가능성을 제시했습니다.

YARV to LLVM의 주요 문제점

  • 성능 불균형: 일부 프로그램에서는 Ruby 1.9보다 느려지는 현상 발생. 이는 Ruby 1.9 런타임을 사용하면서, 네이티브 코드에서 박싱된 데이터를 기대하는 런타임 호출 시 불필요한 박싱/언박싱 오버헤드가 증가하기 때문입니다.

  • 복잡한 타입 추론의 한계: 복잡한 코드(예: 중첩된 블록 호출)에서는 타입 추론이 불가능하여 최적화가 제한됩니다. 타입 추론 과정 자체가 여러 단계를 거치며 실행 시간이 증대되는 문제도 있었습니다.

  • 유지보수 난이도: LLVM 코드 생성과 타입 추론 로직이 혼재된 프로그램 구조로 인해 버그 해결 및 유지보수가 매우 어려웠습니다.

  • 기능 미지원: eval, set_trace_func, BigNum과 같은 Ruby의 동적 기능들(일명 ‘블랙 매직’)은 타입 추론 결과를 무효화시킬 수 있어 구현이 불가능했습니다. 특히 BigNum은 실행 중 메서드 및 스택 데이터 변경이 필요하며 빈번하게 사용되므로 성능 저하 없이 지원하기 어렵습니다.

YTL (YARV Translator)의 개발 및 해결 방안

YARV to LLVM의 한계를 극복하기 위해 YTL이 개발 중입니다. YTL은 풀셋 Ruby 지원을 목표로 하며, LLVM 대신 자체 네이티브 코드 생성 라이브러리인 YTL JIT를 구축합니다. 어셈블러는 Ruby로 작성되었으며, X86 32/64비트 네이티브 코드를 직접 생성합니다.

YTL의 문제 해결 전략

  • 런타임 재구축 및 특수화: 런타임을 Ruby로 작성하여 타입 추론 결과에 따라 특정 타입에 최적화된(specialized) 코드를 생성합니다. 예를 들어, 정수만 다루는 정렬 함수는 정수형에 한정된 코드로 컴파일하여 박싱을 회피합니다. 컴파일 시간 증가는 타입 추론 결과를 마셜링(marshal)하여 재사용함으로써 해결합니다.

  • 타입 추론 개선: 코드 생성과 타입 추론 로직을 분리하고, 타입 추론 처리 자체를 셀프 컴파일하여 네이티브 코드로 실행함으로써 복잡도와 추론 시간 문제를 해결합니다.

  • 동적 컴파일 및 ‘블랙 매직’ 지원: evalBigNum과 같은 동적 기능은 동적 컴파일(On-Stack Replacement)을 통해 지원합니다. 이를 위해 실행 시 스택 프레임 및 객체를 새로운 타입 정보에 맞춰 재작성하는 기술을 활용하며, LLVM에서 어려웠던 스택 프레임 파악을 위해 어셈블러 레벨에서 코드 생성을 직접 제어합니다. 효율적인 동적 재컴파일을 위해 코드 스페이스 구조에도 특별한 설계를 적용하여 기본 블록 단위로 코드를 분할하고, 변경 발생 시 새로운 영역에 재할당하는 방식을 사용합니다.

결론

YARV to LLVM 프로젝트는 Ruby 1.9 VM의 네이티브 코드 변환을 시도했으나, 런타임 의존성으로 인한 박싱 오버헤드, 복잡한 타입 추론의 한계, 유지보수 문제, 그리고 `eval`, `BigNum`과 같은 Ruby의 동적 기능 미지원이라는 세 가지 주요 문제에 직면하여 실패했습니다. 이러한 문제들을 해결하기 위해 개발 중인 YTL은 LLVM을 사용하지 않고 자체 네이티브 코드 생성 라이브러리와 동적 컴파일 방식을 채택하여 풀셋 Ruby 지원을 목표로 합니다. YTL은 런타임을 Ruby로 작성하고, 코드 생성과 타입 추론을 분리하며, 동적 재컴파일을 통해 Ruby의 모든 기능을 고성능으로 지원하는 것을 목표로 합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!