SabiRuby という、Rust で書いた mruby 互換の VM を作っています。mruby のバイトコード(mrbc が出す .mrb)をそのまま実行し、本家の mruby 4.1 と同じに動くことを目指したものです。crates.io に出していて、先日 0.7.0 を公開しました。
- リポジトリ: https://github.com/sabiruby/sabiruby
- ブラウザで試せる Playground: https://sabiruby.github.io/sabiruby-playground/
- Bevy(Rust のゲームエンジン)に組み込む crate: https://github.com/sabiruby/rubevy
先日、h6n さんが Cloudflare Workers 向けの mruby VM「Chiburu」の記事の中で SabiRuby に触れてくれていました(mruby VMをつくった👍📱)。その中に「結局みんな Rust で mruby を作っているなら何が違うのか?」という一文があります。
いい問いだと思ったので、この記事では、SabiRuby がどういう経緯で生まれ、どういう作り方をしているかを書いてみます。ほかの実装との細かい比較ではなく、背景の話です。
きっかけは本だった
2019 年に「mruby バイトコードハンドブック」という同人誌を出しました。mruby の命令を 1 つずつ解説した本です。今、それを土台にした新しい本「Deep dive into mruby」(mruby 4.1 対応)を書いていて、11 月の技術書典に出す予定です。
mruby は 2.0 から 4.1 までの間に、命令の数も、例外処理の仕組みも、コンパイラ(Prism への移行)も大きく変わりました。前の本の内容はほとんどそのままでは使えなくなっていたので、書き直すなら、命令の解説だけでなく、VM・GC・コンパイラまで含めた「mruby の解説書の決定版」にしたいと思いました。
今回の本には、もう一つ目的があります。この本と本家のソースがあれば、別の言語に mruby の VM を移植できる。そういう仕様書として使えることです。
命令の意味を書くだけなら、ソースを読めば分かります。移植する人が本当に知りたいのは、「どこまでを再現しなければならず、どこからは mruby がそう決めただけで選び直してよいのか」という線引きです。たとえば、例外の伝わり方やメソッドの探し方は再現しなければなりません。一方で、値の表現(NaN boxing)や GC の細かい仕組み、setjmp/longjmp は、移植先に合わせて選び直してかまいません。本ではこの線引きを、各章に書いています。
そう書くからには、本当に移植できるのかを確かめたくなります。SabiRuby は、その確かめとして始まりました。本の説明(レジスタの重ね方、OP_ENTER、環境、ensure をまたぐ大域脱出……)を、そのまま Rust に写していく形で作っています。
移植先に Rust を選んだのは、Bevy でゲームを作るときに、ゲームのロジックを Ruby で書きたかったからです。C の mruby を組み込むこともできますが、VM が Rust で書かれていれば、ゲームと同じ言語・同じビルドの中に収まり、ブラウザ(WebAssembly)にもそのまま持っていけます。
何ができるか(2026 年 9 月末の時点)
- 本家 mruby 4.1.0-rc2 の
mrbcが出すバイトコードを実行する(119 命令すべて) - 本家のテストスイートで互換を確かめている(既定のビルドで 2508 件中 2344 件が通る)
- 本家と同じ追跡型の GC、Fiber、mruby-task(タスクスケジューラ)、
eval・binding、require、正規表現、数値の塔(bigint・有理数・複素数)など、本家の gem のほとんど - VM は pure Rust で
no_std(+alloc)。VM の crate にunsafeは 1 行もありません - 本家のコンパイラ(Prism と mruby の codegen)も crate として同梱していて、実行中に Ruby のソースをコンパイルできる
- 速さは、27 本のベンチの合計で本家の 2.57 倍の時間がかかります。つまり遅いです。速さで勝つことより、互換と安全を優先しています
VM が安全な Rust だけで書かれていると、スクリプトの誤りや VM の不具合があっても、メモリが壊れて謎のクラッシュ、ということが構造的に起きません。ゲームに他人の書いたスクリプトを載せる、といった使い方を考えると、この性質はかなり効きます。
Bevy に組み込む: rubevy
作りたかったのは、Bevy の中でゲームのロジックを Ruby で書けることでした。そのためのつなぎが rubevy です。
- スクリプト 1 本が mruby-task のタスク 1 本になり、フレームごとに、命令数の予算の中で動きます
- ゲームに問い合わせて答えを待てます(
Rubevy.ask)。待っている間、タスクは CPU を使いません - ECS のコンポーネントに名前で触れ(
e[:Transform])、Bevy のイベントを受けられます(on(:hit) { ... }) - ゲームを動かしたまま、ゲーム内のエディタでスクリプトを書き換えると、すぐに反映されます
rubevy を使ったサンプルのゲームが 3 本あり、ブラウザで遊べます(3 本の入口: https://sabiruby.github.io/rubevy_games/ )。どれも、ゲームの振る舞いが Ruby のファイルに書かれていて、ゲームを動かしたまま書き換えられます。
- SabiRuby Battle: ロボットどうしが戦うゲーム。ロボット 1 台の振る舞いが Ruby のファイル 1 つです https://sabiruby.github.io/rubevy_games/sabibots/
- 箱庭(Garden): 3D の小さな世界。生き物が自分の ECS のコンポーネントを Ruby から名前で読み書きし、遺伝子を混ぜて増えます。クリックした生き物のファイルをその場で書き換えられます https://sabiruby.github.io/rubevy_games/garden/
- Factory: 上から見る小さな工場。品物やレシピを Ruby で宣言し、工場で起きたことを Ruby で受け、インサーター 1 台ずつが自分のスクリプトで「いつ物を運ぶか」を決めます https://sabiruby.github.io/rubevy_games/factory/
最新の 0.7.0 では、ゲーム用の DSL を書きやすくするために、block の中でも「待つ」ができるようにしました。たとえば instance_exec で評価する DSL の block の中で、タスクがゲームの答えを待てます。
これを作る途中で、本家 mruby の振る舞いを 36 通りの経路で実測しました。すると、本家のほうが待てる経路が多いことが分かり、本に書いていた説明の誤りも 2 か所見つかりました。その結果は本の VM 章に反映しています。VM を作ると本が直り、本を直すと VM が直る。この往復があるのが、本と VM を一緒に作っている面白さです。
作り方: AI と一緒に作る
SabiRuby も rubevy も、ほとんどのコードは Claude Code(Anthropic の AI)が書いています。私の役割は、方針を決めること、計画を承認すること、結果を見て直しを頼むこと、そして公開するかを判断することです。
VM のように、正しさを細かく確かめなければならないものを AI と作るうえで、効いたと思うやり方がいくつかあります。
- 計画書を先に書く。 段階ごとに「到達点」と「どう確かめるか」を決めてから、実装を任せます
- 作業の記録(worklog)を必ず残させる。 何を試して、何を測って、何を捨てたか。後から同じ調査をやり直さないためです。ここに溜まった知見は、本の素材にもなっています
- 本家で確かめる。 振る舞いに迷ったら、本家の mruby を Docker で動かして比べます。推測で書かせません
- 決まり事を短く書いておく。 たとえば「根拠のない数を書かない(測るか、導く)」「VM の crate に
unsafeを入れない」 - 性能は測ってから言う。 変更の前後を交互に何度も測ります。その前に、同じバイナリどうしのばらつきを測って、「遅くなった」とみなす線を決めておきます
うまくいかなかったこともあります。0.7.0 の前に、数 % の性能の差の原因を追いかけさせすぎて、測っては直す、を何巡も続けてしまいました。時間もトークンも有限です。「最初の目標を満たしたら一度止まって報告する」と決めておくことが、AI と長く作業するうえでいちばん大事な決まり事かもしれません。
副産物として、作業の途中で見つけた本家 mruby の不具合について、PR を 3 本出し、マージしてもらいました。
これから
まずは本を仕上げて、11 月の技術書典で頒布します。本と一緒に使う移植キット(検証用のデータとテストの一式)も公開しています。SabiRuby と rubevy は、ゲームで Ruby を使いたい人、mruby を別の環境に持っていきたい人に触ってもらえるとうれしいです。
- 本「Deep dive into mruby」: 11 月の技術書典で頒布予定
- 移植キット: https://github.com/kishima/mruby-porting-kit
- SabiRuby: https://github.com/sabiruby/sabiruby(crates.io:
sabiruby) - rubevy: https://github.com/sabiruby/rubevy(crates.io:
rubevy) - Playground: https://sabiruby.github.io/sabiruby-playground/