以下の内容はhttps://udzura.hatenablog.jp/entry/2026/02/15/182558より取得しました。


mruby/edge 進捗 どうやって

進捗はない... 本質的な課題からも逃げがち... ではありますが、最近mruby/edgeでやってることを殴り書きします。

Playgroundをリリースした

mrubyedge.github.io

しました。正直まだそれなりに機能も足りず、バグもあるでしょうが、遊んでやってください。

1.1.0 で mruby/c と同じぐらいの数のメソッドを実装した(つもりな)ので、Rubyっぽいコードを試しやすくなってる気がします。気持ちの問題かもしれない。なおこの記事を書いてる時点では 1.1.5 が最新ということになっています。

github.com

mruby/edgeとしてはあとは math, json, regexp, random そして mruby-compiler2 と、 mruby-compiler2 の動作に必要なemscriptenの関数を含んでいます。

github.com

これだけ詰め込んでもまだ容量はギリ 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を評価できるようにしました。

github.com

元々の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の真似)。

現状、 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:ただ、今だによくわからないオプションがある...




以上の内容はhttps://udzura.hatenablog.jp/entry/2026/02/15/182558より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14