Ruby 코드를 독립 실행형 네이티브 바이너리로 바꾸고, 전체 프로그램 단위 타입 추론과 C 코드 생성을 통해 최신 CRuby miniruby 대비 기하평균 약 11.6배 빠른 실행을 노림
컴파일 파이프라인은 Prism 기반 파서로 Ruby를 AST 텍스트로 바꾼 뒤 self-hosting 백엔드가 타입 추론과 C 코드 생성을 수행하고, 표준 C 컴파일러로 standalone 바이너리를 만듦
컴파일러 백엔드는 Ruby로 작성된 self-hosting 구조를 갖고 있으며, 부트스트랩 과정을 거쳐 gen2.c == gen3.c가 성립해 자기 자신을 다시 컴파일하는 루프가 닫힘
문자열 연결 평탄화, value-type promotion, loop-invariant length hoisting, static symbol interning, bigint 자동 승격 같은 컴파일 타임 최적화를 넣고, 내장 regexp 엔진과 bigint, 단일 헤더 런타임으로 외부 런타임 의존성을 줄임
eval, 메타프로그래밍, Thread, 일반적인 인코딩 처리는 지원하지 않지만, Ruby 없이 실행되는 배포 형태와 계산 집약적 워크로드에서의 큰 성능 차이로 Ruby AOT 컴파일의 실용성이 드러남
동작 방식
컴파일 파이프라인은 Ruby 파일을 파싱해 AST 텍스트 파일로 직렬화한 뒤, 타입 추론과 C 코드 생성을 거쳐 표준 C 컴파일러로 네이티브 바이너리를 만드는 흐름으로 이루어짐
spinel_parse는 Prism과 libprism을 사용해 Ruby를 파싱하며, C 바이너리가 없을 때는 CRuby와 Prism gem을 사용하는 대체 경로를 사용함
spinel_codegen은 self-hosted 네이티브 바이너리로 동작하며, AST를 받아 타입 추론 + C 코드 생성을 수행함
최종 단계는 cc -O2 -Ilib -lm으로 C 소스와 런타임 헤더를 함께 컴파일하며, 결과 바이너리는 standalone 형태로 만들어짐
Self-Hosting
부트스트랩 체인은 CRuby + spinel_parse.rb로 AST를 만들고, CRuby + spinel_codegen.rb로 gen1.c와 bin1을 만든 뒤, 다시 생성된 바이너리로 gen2.c, gen3.c를 만드는 방식으로 닫힘
gen2.c == gen3.c가 성립해 bootstrap loop가 닫혔음을 명시함
백엔드인 spinel_codegen.rb는 Spinel이 직접 컴파일 가능한 Ruby 부분집합으로 작성됨
classes, def, attr_accessor
if/case/while
each/map/select, yield
begin/rescue
String, Array, Hash 연산과 File I/O
백엔드에는 metaprogramming, eval, require를 넣지 않음
성능과 벤치마크
테스트는 74개 통과, 벤치마크는 55개 통과 상태임
28개 벤치마크 기준 기하평균은 최신 CRuby miniruby 대비 약 11.6배 빠름
비교 기준은 번들 gem이 없는 최신 CRuby miniruby 빌드이며, 시스템 ruby 3.2.3보다 더 빠른 기준과 비교했어도 계산 집약적 워크로드에서 우위가 큼
계산 성능
life는 20ms 대 1,733ms로 86.7배 빠름
ackermann은 5ms 대 374ms로 74.8배 빠름
mandelbrot는 25ms 대 1,453ms로 58.1배 빠름
fib 재귀 버전은 17ms 대 581ms로 34.2배 빠름
nqueens는 10ms 대 304ms로 30.4배 빠름
tarai는 16ms 대 461ms로 28.8배 빠름
tak는 22ms 대 532ms로 24.2배 빠름
matmul은 13ms 대 313ms로 24.1배 빠름
sudoku는 6ms 대 102ms로 17.0배 빠름
partial_sums는 93ms 대 1,498ms로 16.1배 빠름
fannkuch는 2ms 대 19ms로 9.5배 빠름
sieve는 39ms 대 332ms로 8.5배 빠름
fasta는 3ms 대 21ms로 7.0배 빠름
데이터 구조와 GC
rbtree는 24ms 대 543ms로 22.6배 빠름
splay tree는 14ms 대 195ms로 13.9배 빠름
huffman은 6ms 대 59ms로 9.8배 빠름
so_lists는 76ms 대 410ms로 5.4배 빠름
binary_trees는 11ms 대 40ms로 3.6배 빠름
linked_list는 136ms 대 388ms로 2.9배 빠름
gcbench는 1,845ms 대 3,641ms로 2.0배 빠름
실제 프로그램
json_parse는 39ms 대 394ms로 10.1배 빠름
bigint_fib 1000자리 계산은 2ms 대 16ms로 8.0배 빠름
ao_render는 417ms 대 3,334ms로 8.0배 빠름
pidigits는 2ms 대 13ms로 6.5배 빠름
str_concat는 2ms 대 13ms로 6.5배 빠름
template engine은 152ms 대 936ms로 6.2배 빠름
csv_process는 234ms 대 860ms로 3.7배 빠름
io_wordcount는 33ms 대 97ms로 2.9배 빠름
지원하는 Ruby 기능
Core 기능으로 classes, inheritance, super, include 믹스인, attr_accessor, Struct.new, alias, module constants, 내장 타입에 대한 open classes를 지원함