ZJIT는 YJIT의 경험을 바탕으로, 보다 유지보수 가능하고 확장성 있는 아키텍처를 목표로 합니다. YJIT가 Yarv 바이트코드를 직접 머신 코드로 컴파일하는 단순한 구조였던 반면, ZJIT는 두 가지 핵심적인 설계 변경을 도입합니다. 첫째, ZJIT는 Lazy Basic Block Versioning 대신 전통적인 ‘메서드 기반 JIT 컴파일러’ 방식을 채택합니다. 이는 컴파일러 교과서에서 다루는 표준적인 접근 방식으로, 위험을 최소화하고 성공 가능성을 높이며, Ruby 커뮤니티의 참여를 용이하게 합니다. 둘째, ZJIT는 자체적인 ‘중간 표현(IR)’을 가집니다. YJIT가 MRI 인터프리터를 위해 설계된 Yarv 바이트코드를 사용했던 것과 달리, ZJIT는 JIT 컴파일러에 최적화된 SSA(Static Single Assignment) 기반 IR을 사용하여 복잡한 의미론을 작고 조합 가능한 기본 요소로 분해하고 코드 최적화를 용이하게 합니다. 이는 JavaScript JIT와 같은 다른 고성능 언어의 JIT 컴파일러에서 널리 사용되는 검증된 방식입니다.
ZJIT는 두 가지 주요 기능을 통해 성능을 더욱 향상시킬 계획입니다. 첫째, ‘빠른 JIT-to-JIT 호출’입니다. 기존 Ruby VM의 복잡한 호출 오버헤드를 줄이기 위해, ZJIT는 CPU의 call
및 return
명령어를 직접 활용하고 C 스택을 사용하여 JIT 함수 간 호출을 최적화합니다. 초기 실험 결과, 재귀 피보나치 벤치마크에서 YJIT보다 60% 더 빠른 성능을 보여주며 매우 고무적인 결과를 얻었습니다. 둘째, ‘컴파일 작업의 직렬화 및 재사용’ 기능입니다. 이는 컴파일된 머신 코드를 저장하고 재사용하여 애플리케이션의 워밍업 시간을 단축하고, 더 높은 최적화 수준에 도달하기 위해 컴파일에 더 많은 시간을 할애할 수 있도록 합니다. 대규모 서버 환경에서 코드 재배포 시 발생하는 비효율성을 줄이는 데 큰 도움이 될 것입니다.
현재 ZJIT는 개발 초기 단계임에도 불구하고, 이미 사용자 정의 SSA IR, 제어 흐름, 빠른 JIT-to-JIT 호출, 상수 및 타입 전파, 데드 코드 제거 등 핵심 기능을 구현했습니다. 단순한 마이크로 벤치마크에서는 인터프리터 및 YJIT보다 빠른 성능을 보여주고 있습니다. ZJIT의 업스트림(C Ruby에 통합) 제안은 Ruby 코어 멤버들로부터 긍정적인 반응을 얻었으며, 몇 주 내에 이루어질 것으로 예상됩니다. Ruby 3.5에서는 YJIT가 여전히 사용 가능하며, ZJIT는 선택적 베타 기능으로 포함될 가능성이 높습니다. 개발팀은 올해 말까지 ZJIT가 YJIT의 성능을 능가하고 더 현실적인 벤치마크에서 우위를 점할 것으로 기대하고 있습니다.