進捗はない... 本質的な課題からも逃げがち... ではありますが、最近mruby/edgeでやってることを殴り書きします。
Playgroundをリリースした
しました。正直まだそれなりに機能も足りず、バグもあるでしょうが、遊んでやってください。
1.1.0 で mruby/c と同じぐらいの数のメソッドを実装した(つもりな)ので、Rubyっぽいコードを試しやすくなってる気がします。気持ちの問題かもしれない。なおこの記事を書いてる時点では 1.1.5 が最新ということになっています。
mruby/edgeとしてはあとは math, json, regexp, random そして mruby-compiler2 と、 mruby-compiler2 の動作に必要なemscriptenの関数を含んでいます。
これだけ詰め込んでもまだ容量はギリ 1 MB を切っている。
$ ls -lh docs/*.wasm -rwxr-xr-x 1 udzura staff 922K 2月 15 15:15 docs/playground.wasm*
regexp がRustのregexベースで、でかいことがわかっているので若干工夫したいと思っています。このgem欲しい!とかあったら教えてください。
あとはPlaygroundなどを支える技術を...。
mruby-compiler2 ベースでその場でRubyを評価できるようにした
まず、非常にポータブルで、かつ使いやすいmrubyコンパイラライブラリ実装であるmruby-compiler2を組み込んで、その場でRubyを評価できるようにしました。
元々のmrbcは、コマンドラインツールとコンパイラがウルトラ密結合なので、この仕事は本当に本当に偉業です。せめてただ使うだけじゃなく何か貢献したい... がんばります...。中で使われているPrismもありがとう。
ただ、mruby-compiler2はsetjmp/longjmpを用いた箇所があり、Rustでいう wasm32-unknown-unknown ターゲットへのコンパイルはやや難しくなっています。今回はブラウザで使えればいいので Emscripten のsetjmp/longjmpサポートをそのまま使うようにしました。若干ガチャガチャしたらRustからも使えたので助かった*1。
書いてたコードを保存してシェアできるようにしてみた
Playgroundを作るときに思いついて実装しました。以下が雑な図です。

Playground自体は mrubyedge.github.io ドメインが良かったので、Cloudflare WorkersにAPIを立てて、CORSで許可して通信させることにしました。もちろん、Cloudflare Workersでもmruby/edgeが動いています。
一緒にmruby/edgeからもDurable Objectを触れるようにしたんですが、ちょっと制限があって、Cloudflare WorkersのJavaScriptレベルではDurable Objectに触れる関数が非同期だったので、Wasmのimport関数の中ではうまく呼べません。したがって中身のfetchが必要なときはpreflight的にfetchしてから使わせるようにしてお茶を濁しました。
ちゃんと外部のasyncな関数を呼ぶには、例えばmruby/edgeの実行を途中で止めて再開できるようにすればいいでしょう。ただ、Rubyのコード(mrubyのバイトコード)だけなら多分できるんですが、内部でRustの関数を呼ぶパターンが...。Rustの関数は中断しなければいいかと思いつつ、Rustの関数の中で普通にブロックを呼んでいるパターン(Enumerable#each、Integer#times)があるので、何かしら発明がないとダメそう。
とはいえ全体的に自作Rubyを使いながらこういう開発ができるので、良い気分です。
TODOs
インターネットに公開したのでそれなりに安全にはしたくて、今今、たまたま while 文が動かないんですが、これは動くようにしつつ、ビルド時にVMが実行できる最大の命令数を指定する機能をつけようと思います(eBPFのverifierの真似)。
mruby/edgeなんかwhile文動いてないな。バイトコードを見たら、wasmのノリで後ろ向きのJMPを実装してないように見える。安全すぎるな
— Uchio Kondo💥 (@udzura) 2026年2月15日
現状、 Kernel#loop も実装していなくて、while文が動かないのでRubyレベルでは無限ループを実装することはできないはず。また、再起はmruby/edgeの全体のレジスタ長が制限されているおかげで最終的に例外になります。ということでコードを実行したらブラウザが固まる状況は簡単には起せないでしょう(そもそもWasm経由の実行なのでめちゃくちゃ危険な状況もないでしょうが...)。良かった、今はそこそこ安全だ〜(?)。
再起のエラーはエラーメッセージをどうにかしたり、あとレジスタ長もビルド時に変えられるようにしたい。
それから運用面の安全性では、最低限ですが report abuse ボタンはつけようと思っています。なんならもう report abuse されたら勝手に時間経過で消えていいと思う。
あとは、データをたくさんつくられると困るとは思うんですが、まあこれは単に保存できなくなるだけかなと。 Cloudflare WorkersのDurable Objectで一定時間経ったら勝手に消える実装ってシュッとできるんだろうか。
とにかく、作ると作りたいものが増えるので、じわじわやっていきます。「盆栽」ですから無理のない範囲で...。
REPL を実装した
ついででもないですが、上記でコンパイラとの統合自体は動いたということで、 mrubyedge-cli にもREPLを実装しました。以下で試せます。
$ cargo install mrubyedge-cli@1.1.5
$ mrbedge repl
mruby/edge REPL (1.1.5)
Type 'exit[↩]' or press Ctrl+D to quit
Press Enter to execute, Option+Enter(Shift+Enter also supported in iTerm2) for line continuation
repl:001> a = 1
=> 1
repl:002> b = 2
=> 2
repl:003> puts "answer = #{1 + 2}"
answer = 3
=> nil
repl:004>
変数の定義済み情報を継続できないよ〜と思っていたら、 PICORB_VM_MRUBYC などを定義してcontextをそのまま維持すれば大丈夫でした...。今までちょっとした動作確認でも毎回Rustでexampleを作ってビルドしてたので、楽になって嬉しい。
という感じで徐々に進歩しています。Wasm向けに作ってはいるんですが、Wasmでの動作は制限が厳しいので後で勉強するとして、自分が使えるようにGoogle Cloudの各種機能のライブラリを作ってCloud Runとかで動かしやすくしようかなとか思っているところ...。
一応書いておくと、特にRubyとしての標準ライブラリの部分や、Playgroundのコードは、かなりの部分AIに書かせています(主にCopilot + Claude Sonnet 4.5 が多い)。もちろん、生成されたコードは全部自分でレビューして、割と手直しもした形で動かしています。
*1:ただ、今だによくわからないオプションがある...