The Ruby Compiler Survey

The Ruby Compiler Survey is a project cataloguing, preserving, and dissecting compilers for the Ruby programming language. In this context, a compiler is something that eventually produces machine code from Ruby code, whether that’s ahead-of-time or just-in-time. There are a surprisingly large number of attempts to write compilers for Ruby, using very varied approaches, so a comparative study is interesting. Some of these compilers were being lost to time and action was needed now to preserve and document them.

We’re interested in how these compilers are designed and implemented, their history, and the output they produce. We’re focusing on compilation in order to keep the project in some kind of scope, but we’ll describe other parts of the implementation, such as the garbage collector or interpreter, where they’re relevant. We apply some judgement for how much we consider to be part of the Ruby implementation. For example where components are shared between multiple language implementations, we consider them to be part of the Ruby compiler when they are co-developed. Some of these compilers are much more serious than others - several of them are learning exercises, demos, or toys.

This isn’t a benchmarking game and this isn’t a competition. The compilers target a variety of architectures and have diverse goals beyond simple performance so comparing quantitatively would not make sense. We aim to be objective but we do offer informed commentary on the techniques employed and how successful they are in producing efficient machine code from Ruby. The author is the founder of the TruffleRuby compiler but is trying to be neutral.

There’s a page describing each compiler implementation, and an appendix describing how to build and use it. We assume medium-to-expert knowledge of compilers. Much of the information in this site is archaeological, so we apologies for any omissions or errors. Corrections welcome.

The compilers

Compiler Years active Base VM Stage General approach Frontend Interpreter Intermediate representations Key authors
Hokstad 2008-present Custom Ruby AOT Template compilation of an AST Custom recursive descent and operator precedence parser None Enhanced AST Hokstad
Hyperdrive 2019-2020 MRI JIT Tracing of YARV instructions then template compilation to Cranelift Tracing YARV interpreter Instrumented base interpreter None Matthews
IronRuby 2007-2011 Custom C# JIT Generation of CIL Lam
JRuby 2006-present Custom Java JIT 1 Generation of JVM bytecode Parser to AST, to internal IR Internal IR interpreter CFG of linear RTL instructions Nutter, Enebo, Sastry
LLRB 2017 MRI JIT Generation of LLVM IR Kokubun
Ludicrous 2008-2009 MRI JIT Template compilation through DotGNU LibJIT Brannan
MacRuby 2008-2013 MRI AOT/JIT Generation of LLVM IR Sansonetti
MagLev 2008-2016 Custom Gemstone Smalltalk JIT McLain, Felgentreff
MRuby JIT Hideki
Natalie 2019-present Custom C++ AOT AST incrementally lowered to C++ Enhanced AST Morgan
Ruby+OMR 2016-2017 MRI JIT Generation of J9 IR Gaudet, Stoodley
RTL MJIT 2017 MRI JIT Generation of C Makarov
Rubinius 2008-2016 Custom C++ and Ruby JIT Generation of LLVM IR Parser to AST, to custom stack bytecode Stack bytecode None Phoenix, Bussink, Shirai
RuJIT 2015 MRI JIT Tracing Ide
Rhizome 2017 MRI, JRuby, Rubinius JIT Conventional speculative compiler with in-process assembler Base bytecode or IR to custom bytecode Stack bytecode Graphical sea-of-nodes Seaton
RubyComp 2004 AOT Alexandersson
RubyX 2014-2020 AOT Conventional compiler with in-process assembler Parser to AST None Multiple IRs gradually removing abstraction and lowering from AST to linear Rüger
Ruby.NET 2008 Custom C# Generation of CIL Kelly
Rucy 2021 AOT Template compilation to eBPF Uchio
Sorbet 2019-present MRI AOT Generation of MRI LLVM IR 'C' extension Parser to AST None Sorbet's typechecking IR Tarjan, Petrashko, Froyd
TenderJIT 2021 MRI JIT Lazy Basic Block Versioning with in-process assembler Template compiler of YARV bytecode Base interpreter None Patterson
Topaz 2012-2014 Custom RPython and Ruby JIT Metatracing of a stack bytecode interpreter Parser to AST Stack bytecode interpreter Gaynor, Felgentreff
TruffleRuby 2013-present Custom Java and Ruby JIT Partial evaluation of self-specialising AST Parser to AST Self-specialising AST interpreter Graphical sea-of-nodes Seaton, Daloze, Menard, Chalupa, MacGregor
XRuby 2006-2008 Custom Java AOT Template compilation to Java bytecode Parser to AST None None Zhi
yarv2llvm 2008-2010 MRI JIT Generation of LLVM IR Hideki
YARV MJIT 2018-present MRI JIT Generation of C Base interpreter Kokubun
YJIT 2020-present MRI JIT Lazy Basic-Block Versioning with in-process assembler Template compiler of YARV bytecode Base interpreter None Chevalier-Boisvert
YTL 2009-2014 Hideki
  1. JRuby also includes an AOT mode, but today this just embeds the interpreter and IR

Wilson is a Ruby library for assembling IA-32 machine code.

ronin-asm is a Ruby library for assembling IA-32 and AMD64 machine code.

Fisk is a Ruby library for assembling AMD64 machine code.

Ruby Compiler is a tool to package Ruby code with a Ruby interpreter, giving a stand-alone executable, but not actually translating the Ruby code to machine code.

Sources

We use a running set of example programs throughout the survey.

The ruby-compiler-survey repository contains this content, files that can be used to build and run the compilers, including in some cases patches, and output taken at the time of writing the survey. Compiler source code itself is archived in the ruby-compiler-survey GitHub organisation where possible.