Ruby implementation with yet another JIT compiler written in Rust.
- 📖 Documentation — installation and build, development and build options, benchmark, compatibility and the full changelog, plus architecture overviews and the design documents.
- 📊 Project portal — benchmark and ruby/spec dashboards, re-measured on every push to
masterthat touches the interpreter.
Highlights from the last two months; earlier months are in the changelog, linked at the end of this section.
- Real-application benchmarking drive (ruby-bench / yjit-bench: railsbench, lobsters, fluentd, activerecord, erubi, graphql) with a long run of runtime fast paths: frame-free leaf and
Foo.newexpansion, machine-codeHash#[]probes, a seeded hash mixer, in-place string/array building, and lazy rubygems boot (#1217, #1240, #1247, #1255, #1261, #1263, #1313, #1365, #1547, #1601). - GC work: resident allocation budgets, ~45% faster marking, promotion of leaf object types, prefetching queued marks, and releasing JIT pages and thread heaps (#1238, #1252, #1256, #1259, #1262, #1300, #1466, #1484).
- JIT and chain-deopt refinement: shared abstract-state frames, polymorphic compare/send handling, method specialization with float registers, and compile-unit-scoped chain deopt, plus a series of
ensure/non-local-exit splicing fixes (#1270–#1277, #1326–#1337, #1351, #1363, #1370–#1375, #1664, #1667). - Native extensions and stdlib stand-ins: a dynamically loaded
mr_*extension ABI with sqlite3 / zlib / zstd / psych / nokogiri moved out of the core, a relocatable install tree, plus Nokogiri (XML, SAX, HTML5, XSLT), Psych over a libyaml port, Prism/Ripper,io/console, the json 2.18 port, and fluentd/lobsters C-extension stand-ins (#1299, #1302, #1304, #1306–#1312, #1314, #1387, #1391, #1393, #1409, #1419, #1649). - Encoding overhaul: CRuby's own CJK/ISO/Windows tables,
Encoding::Converterwith UTF-16/32 and its own object type, regexps in every encoding, and a phased encoding plan with a measurement matrix (#1437, #1463, #1515, #1550, #1564, #1594, #1626, #1629, #1630, #1632, #1637–#1641). - Threads: a 1:1 kernel-thread model behind a GVL — signals, fork, JIT/BOP eviction across threads — landed in phases P0–P7 and became the default;
Fiber.schedule,Regexptimeouts and per-thread autoload visibility came along (#1443, #1446, #1678–#1685, #1687). - ruby/spec and fidelity fixes grouped across Time (zones, exact sub-seconds, strftime), Marshal, ENV, Struct/Data, Float/Rational rounding, Enumerator, and method reflection; the reference CRuby pin moved to 4.0.6 (#1402, #1406, #1412, #1428, #1430, #1436, #1442, #1645, #1659, #1682).
- aarch64 and CI: aarch64 stub reach past ±128MB and ivar-store fixes, daily arm64 benchmarking, and ZJIT as a third benchmark engine (#1217, #1338, #1415, #1680, #1686).
- Broad early-month ruby/spec compliance drive across Kernel, Enumerator, IO and process handling:
Enumerator::Lazy/Product/Chain, fiber-free#each/#with_indexinternals, ARGF reimplemented in Rust, Refinements, and a full spawn-exec engine with realDatasubclasses (#1039–#1065, notably #1046, #1054, #1064). - Signal delivery moved onto gated safepoint polls, and the safepoint word was reworked into one process-global, four-byte-lane poll;
gc-stressthen went opt-in and ran at every safepoint on both arches, catching a string of unrooted-Valueand FP-pool bugs (#1070–#1075, #1123–#1125). - Hash subsystem overhaul: an AR-mode small-hash table embedded directly in the
RValuecell, JIT-inlined accessors ([]=,size,default, …), and correctness fixes for tombstone deletes and iteration order (#1060, #1086–#1108). - JIT dispatch modernization: polymorphic call and comparison sites now dispatch through the PIC instead of guarding and evicting, with BinOp/BinCmp lowering unified into one skeleton (#1110, #1127–#1133).
- Chain deopt became the sole recovery path off a stale JIT frame, followed by a multi-week abstract-state and frame-chain rework (unified joins, outer-frame float promotion across block calls) that got the ActiveRecord benchmark running both correctly and fast (#1134, #1136, #1149–#1168, #1171–#1198).
- aarch64 kept pace with the chain-deopt work: outlined side-exit islands, branch-range relaxation past the
Imm19reach, and ports of the class-version recovery jump-back (#1153, #1175, #1176, #1182, #1183, #1189). - Late-month perf sprint: cached
Symbol#to_procprocs, dispatch-free Array/Range scans and equality-by-identity fast paths, plus a JIT correctness fix for inlinedsendandmethod_missingdispatch (#1200–#1214). - Consolidated the README and wiki into the mdBook documentation site and added this generated Changelog chapter (#1215, #1216).
Earlier months: Changelog (from January 2026), and Progress summary (April 2025 – April 2026) for a prose account of the same period.
- Presentation movie and slides for RubyKaigi2024 is here.
- Presentation movie and slides for RubyKaigi2025 is here.
- Written in Rust from scratch. No dependencies on any other Ruby implementations.
- Fast. Currently, monoruby is comparable to ruby 4.0.5+YJIT/ZJIT on many benchmarks, not just optcarrot.
- Parses Ruby source with prism, the official Ruby parser (the original hand-written parser was replaced in May 2026).
- Register-based bytecode.
- Bytecode executor (virtual machine) emitting machine code directly, for both x86-64 and aarch64 (Apple Silicon).
- A compact and fast just-in-time compiler with full backends for x86-64 and aarch64. (internally using self-made dynamic assembler monoasm)
Conformance with Ruby has improved dramatically over the course of 2026, driven by an extensive ruby/spec-based compliance effort.
Pass rates are re-measured on every interpreter change and published on the project portal: as of commit a13bfe0 (2026-08-31) monoruby passes 97.6% of the core specs (22468 / 23029 examples) and 59.1% of the library specs.
As of July 2026 it also passed 100% of the command-line specs and 99.6% of the language specs.
Daily-updated pass statistics, compared with CRuby / TruffleRuby / JRuby, are published at rubyspec-stats.
The Compatibility chapter of the documentation breaks the numbers down by category, explains how they are measured, and lists the behaviours that differ from CRuby by design.
- x86-64 Linux
- aarch64 — macOS on Apple Silicon is fully supported (VM + JIT); CI runs natively on GitHub's Apple Silicon (
macos-latest) runners. Linux arm64 works as well.
See Installation and Build for prebuilt binaries, platform notes, what the build installs, and the full command-line reference.
(1) Install Rust.
Check here to install Rust if you have no Rust yet.
Caution!! only nightly Rust works for monoruby. You do not have to select the channel yourself: rust-toolchain.toml pins the exact nightly the project is tested against, and rustup installs and uses it automatically the first time you run cargo in the checkout.
(2) Clone this repository.
> git clone https://github.com/sisshiki1969/monoruby.git
> cd monoruby(3) Build and run monoruby with Ruby script file.
> cargo run --release -- test.rb(4) or, Launch REPL.
> cargo run --bin irmor
> bin/irm(5) or, install monoruby and irm onto your PATH.
> bin/install # cargo install + the native extensions (psych, zlib, …)
> monoruby test.rb
> irmThis repository doubles as a setup-monoruby action (see action.yml),
modeled after ruby/setup-ruby. The ref
after @ selects the monoruby version to install:
steps:
- uses: sisshiki1969/monoruby@master # or a release tag
- run: monoruby my_script.rbThe action first tries to download a prebuilt binary attached to a GitHub
release (built by the release binaries workflow), which installs in seconds:
release tags use their own release's assets, while @master / @nightly use
the rolling nightly prerelease, rebuilt on every master push (so it
can lag a just-pushed HEAD by one build, ~15 min). Automatic builds cover
x86-64 Linux only; assets for Linux arm64 and macOS arm64 are published on
demand by dispatching the release binaries workflow with the wanted tag and
targets. When no asset exists for the ref/platform — or
prefer-prebuilt: 'false' is set — the action falls back to building monoruby
from source on the first run for each monoruby revision × runner OS/arch and
caches the resulting binary and runtime tree with actions/cache, so
subsequent runs restore in seconds. Linux (x64/arm64) and macOS (Apple
Silicon) hosted runners are supported either way.
Inputs and outputs:
| Name | Kind | Description |
|---|---|---|
prefer-prebuilt ('true') |
input | Set to 'false' to skip release assets and build the exact ref |
cache ('true') |
input | Set to 'false' to disable the source-build cache |
cache-version ('v1') |
input | Mixed into the cache key; bump to discard existing caches |
prebuilt |
output | 'true' if a prebuilt release asset was used |
cache-hit |
output | 'true' if the built binary was restored from cache |
monoruby-version |
output | Output of monoruby --version |
ruby-version |
output | RUBY_VERSION reported by the installed monoruby |
Up-to-date benchmark results (yjit-bench, re-measured on every interpreter change) and the ruby/spec compliance dashboards are published on the project portal. On the x86-64 run of commit a13bfe0 (2026-08-31), over the 59 benchmarks that completed on both interpreters, monoruby averaged 1.28x the speed of CRuby+YJIT (geometric mean).
The Benchmarks chapter of the documentation explains the measurement methodology and how to reproduce a run locally. The numbers below are older one-off measurements, kept for the record.
Several Ruby implementations described below were measured by optcarrot benchmark. See Benchmarks — optcarrot for details.
- ruby 3.4.0dev (2024-04-27T08:56:20Z master 9ea77cb351) [x86_64-linux]
- truffleruby 24.0.1, like ruby 3.2.2, Oracle GraalVM JVM [x86_64-linux]
- truffleruby 24.0.1, like ruby 3.2.2, Oracle GraalVM Native [x86_64-linux]
- monoruby: 3e348afd4141c40978342e67ad26d42dc0b8d2a7
Several Ruby implementations described below were measured by yjit-bench. See Benchmarks — yjit-bench for the raw data.
- monoruby: monoruby 0.3.0
- yjit: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
- truffleruby-24.1.1: truffleruby 24.1.1, like ruby 3.2.4, Oracle GraalVM Native [x86_64-linux]
The graph shows the speed ratio against truffleruby. (higher is better)


