Ruby implementation with yet another JIT compiler written in Rust.
Monthly highlights of improvements since January 2026 (with representative PRs).
- Big language-semantics compliance drive on the ruby/spec "language" group: destructuring, block-argument semantics,
defined?, flip-flops,BEGIN/END, and predefined globals (#804–#874, notably #861). - Implemented pattern matching (
case/in,=>) (#883) and MRI's full eigenclass tower (#877). - Green threads (M:1): scheduler core, real Thread / Mutex / Queue, scheduler-integrated blocking IO, and preemptive timeslice multithreading (#941–#944, #962).
- Real TCP / UDP / UNIX-domain sockets (#964, #981);
IO::Bufferwith mmap file mapping (#927, #931);IO.copy_stream(#924). - Added the
setup-monorubyGitHub Action with prebuilt binaries (#884, #886) and CRuby-compatible command-line option processing (#891). - Completed the Exception API: raise-time backtraces,
full_message, NameError / NoMethodError metadata (#893–#896). - Brought the aarch64 JIT to optimization parity with x86-64 (#993–#1004) and shrank call frames for ~7% faster fib (#850).
- Completed
Fiber— transfer / raise / kill / storage and a real root fiber, making core/fiber fully green (#1036) — and refined Thread semantics: the asyncThread#raiseprotocol and structuredThread::Backtrace::Location(#1026, #1027). - JIT: object allocation emitted as inline machine code (free-list pop + bump) (#1011), guard-free slot dispatch for method calls on aarch64 (#1010), and trivial-method folding through
...forwards (#1012). - Encoding: streaming
Encoding::Converterstate andString#encodefallback / newline decorators (#1018, #1019); Regexp gained native-encoding byte matching for non-UTF-8 subjects plus upstream Onigmo engine fixes (#1037, #1038). - CRuby-compatible
require/load/autoloadresolution rules (#1033), a Rust fnmatch engine backingDir.glob(#1017), and an mdBook documentation site published to the project portal (#1008).
- Completed the aarch64 JIT backend: full AsmInst coverage, inline methods, loop JIT, and recompilation on Apple Silicon (#645–#704).
- Introduced a generational GC (RGenGC-style) (#705); GC now also triggers on malloc growth (#732).
- Completed the Prism migration and removed the old hand-written parser (ruruby-parse) (#657).
- New JIT register allocation: LIR-based lowering with a per-basic-block GP register allocator; retired the R15 accumulator (#741, #756, #763).
- Cut allocation/dispatch overhead by 12–26% on addressable benchmarks (#708); zero-copy String operations (gsub, slice, lines, scan) (#722–#724).
- Made the build host-Ruby independent and reproducible (#769).
- Switched the parser to Prism, the official Ruby parser (#412).
- Encoding subsystem overhaul: real
String#encode(#443),Encoding::Converter(#447, #451), ISO-2022-JP (#449), and EUC-JP / Shift_JIS-aware string operations (#536–#545). - Native String fast paths (
reverse,rindex, case mapping, …) that beat YJIT (#493–#497); dropped per-builtincatch_unwindfor +8–10% on optcarrot (#501). - JIT: virtual FP registers with spill-to-stack (#387), heap-constant folding and
Object#is_a?inlining (#504, #505), non-deopting polymorphic comparisons (#519). - Decoupled monoruby from any host Ruby installation (#579, #595); completed the Marshal format tags (#588–#603); real
File::Stat(#607); frame-local$~/$_(#608). - Started the aarch64 port: VM-tier backend and macOS (Apple Silicon) support (#640, #641, #644).
- Continuous yjit-bench benchmarking against YJIT, charted on GitHub Pages (#411, #416).
- Reimplemented
Rationalas a first-class Rust type with literal support (#266). - Broad ruby/spec compliance work on Integer / Float / Array / Symbol / Class / Module (e.g. #281, #284, #309), with a live spec dashboard published on GitHub Pages (#364, #365).
- Moved shift / bitwise /
**/%into the inline-function JIT pipeline with constant folding (#307, #308), and added frame-free trivial-method optimization viaISeqHint(#290). - Struct: per-instance slot storage with JIT-inlined member accessors (#367–#369).
- String: encoding-aware data model — code ranges,
Encoding::CompatibilityError, encoding-aware char iteration (#382–#384). - Reworked
autoloadas a proper state machine (#376) and added lazy heap promotion for Proc / Lambda / Binding captures (#332).
- Implemented
Marshal.dump/Marshal.load(#121, #125) and theSetclass, a CRuby 4.0 built-in (#130). - Implemented the
retrystatement (#109), module/class lifecycle hooks (#127), anonymous block forwarding (#128), and regex backreferences / special variables (#129). - Added
Kernel.#load(#105), correctDir.glob(#106),Kernel.#format/sprintf(#162), and a SQLite3 FFI bridge for the sqlite3 gem (#160). - Started a large ruby/spec compatibility push: implicit type conversions (#225), frozen-object support (#240), Errno exceptions (#250), and many crash fixes on invalid UTF-8 input (#209–#212).
- Fixed many issues to run optcarrot (#115) and the rubyboy / lee benchmarks (#111, #120).
- Optimized rest / keyword-rest parameters in the JIT (#96).
- Corrected
/and%semantics for Integer and Float (#97) and fixedInteger#digits(#99). - Optimized the Range class (#98) and fixed
Range#include?for string / beginless / endless ranges (#104). - Introduced continuation frames (#101) and reworked JIT slot write-back logic (#102).
- Hardened JIT frame handling so local frames are never captured by JIT-compiled code (#93).
- Added
SAFETYcomments tounsafeblocks across the codebase (#94). - Introduced immediate operands (
BytecodeInst::Immediate) into the bytecode (#95).
- 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. As of July 2026, monoruby passes 100% of the command-line specs, 99.6% of the language specs, and about 90% of the core-library specs. Daily-updated pass statistics, compared with CRuby / TruffleRuby / JRuby, are published at rubyspec-stats.
- 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.
Please see wiki for details.
(1) Install nightly Rust.
First of all, install Rust nightly. Check here to install Rust
Caution!! only nightly Rust works for monoruby. See here to work with nightly Rust.
(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/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, measured on every push to master) and a ruby/spec compliance dashboard are published on the project portal. The numbers below are from older one-off measurements.
Several Ruby implementations described below were measured by optcarrot benchmark. Please see wiki 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. Please see wiki for details.
- 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)


