YARV는 루비 애플리케이션 스택의 하위 계층에서 작동하며, 루비 스크립트를 추상 구문 트리(AST)로 파싱한 후 루비 바이트코드로 번역하여 실행하는 스택 머신 모델을 채택했습니다. 이는 이전 루비 1.8 버전에서 AST를 직접 평가하던 방식에 비해 효율성을 크게 높였습니다. YARV의 핵심 아이디어 중 하나는 자동 명령어 생성입니다. 단일 파일에서 가상 머신 명령어를 정의하면 실행 코드, 메타데이터, 역어셈블러, 문서 등이 자동으로 생성되어 지루한 코드 작성을 줄이고 최적화를 용이하게 합니다.
루비는 매우 동적인 언어 특성 때문에 최적화에 제약이 많습니다. 예를 들어, 1 + 2
와 같은 간단한 연산도 Integer#+
메서드가 재정의될 수 있어 컴파일 시점에 결과를 예측하기 어렵습니다. 또한, 루비는 메서드 호출이 매우 잦아 메서드 디스패치 최적화가 중요하며, YARV는 메서드 캐싱 및 특수화된 명령어 도입을 통해 이를 개선했습니다. 특히, 블록(클로저) 생성 시 로컬 변수의 캡슐화를 필요한 시점까지 지연시키는 ‘지연된 Proc 생성(lazy proc creation)’ 기술은 루비 1.8의 성능 저하 원인을 해결하며 실행 속도를 획기적으로 향상시켰습니다.
YARV 개발의 주요 성과로는 루비 가상 머신 자체의 정의와 복잡한 루비 명세(메서드 파라미터, 블록 파라미터, 예외 처리 등)를 가상 머신 명령어로 구현하여 다양한 최적화 기법을 적용할 수 있게 된 점입니다. 또한, 사람이 읽기 쉬운 명령어 명칭을 도입하고, BootSnap
을 위한 바이너리 표현 방식 및 루비 내장 메서드를 루비 코드로 작성할 수 있게 한 prelude.rb
도입도 중요한 기여입니다.
아쉬운 점으로는 초기 설계가 ‘변경 용이성’에 중점을 두어 JVM이나 CLR처럼 ‘잘 정의된 명령어 집합’을 갖추지 못했다는 점입니다. 이로 인해 현재는 기존 명령어 변경이 어렵습니다. 또한, 발표자는 JIT(Just-In-Time) 컴파일러 개발에 직접 참여하지 못한 점을 아쉬워했지만, Shopify의 YJIT과 같이 외부 팀의 성과를 존중하며, JIT 없이도 가상 머신 자체의 성능을 개선하는 것이 중요하다고 강조합니다. 메서드 인라이닝 기술의 부재와 특수화된 명령어의 확장성 부족, 그리고 블록 디스패치 최적화의 미흡함도 개선해야 할 과제로 언급되었습니다. 현재 루비 코드로 구현된 부분이 늘어나면서 부트 타임 로딩 시간이 길어지는 문제가 있으며, 이를 해결하기 위한 지연 로딩(lazy loading) 기술의 활성화가 필요합니다.