ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

mruby/edge のVMを書き換えた

明けましておめでとうございます!

タイトルの通り。mruby/edge のVMを、mruby/c 1.2 相当の内容に書き換えた。

mruby/c 1.2 の実装は以前軽く読んだ。

udzura.hatenablog.jp

PRはめちゃでかい。 +2,605 −1,376 だそうです。

github.com

合わせてcrateをいくつかリリースした。

mruby/edgeとmecのcrateを更新した。以下でmecを更新してください。なぜかもう rc3 ですが、ええじゃないですか。

$ cargo install mec --version=1.0.0-rc3
$ mec --version                        
Version: 1.0.0-rc3

今RCでリリースしているバージョンでは、ちゃんとクラスを定義してオブジェクトを作ることが...できる! 以下のようなRubyスクリプトを用意して、

class MyMRubyClass
  def initialize(value)
    @value = value
  end

  def update(value)
    @value = value * 2
  end

  def value
    @value
  end

  def print_self
    puts "Value: #{value}"
  end
end

def main
  obj = MyMRubyClass.new(123)
  obj.print_self
  obj.update(456)
  obj.print_self
  return obj.value
end

以下のようにwasmバイナリにコンパイルしたら、

$ mec --fnname main examples/object.rb 
running: `cp /Users/udzura/ghq/github.com/udzura/mrubyedge/mec/examples/object.rb src/`
running: `mrbc src/object.rb`
running: `cargo build --target wasm32-wasip1 --release`
running: `cp ./target/wasm32-wasip1/release/mywasm.wasm /Users/udzura/ghq/github.com/udzura/mrubyedge/mec/object.wasm`
running: `cd .. && rm -rf work-mrubyedge-r6uYcPUZkjTYN17nL04bPff0dbfSrLP9`
[ok] wasm file is generated: object.wasm

wasmtimeで実行できる。すごい! オブジェクト指向スクリプト言語 for WASMじゃん。

$ wasmtime --invoke main object.wasm 
Value: 123
Value: 912

実装した命令など

optable.rs を見るとわかる。なんとなく半分超えぐらいか?

github.com

しかし、たとえば GETUPVAR とか、正しい実装なのかよくわからない。命令が出るRubyスクリプトを探しつつ地道にデバッグするしかない。mruby/c 1.2でサポートされているものを優先して実装しているが、mruby/c 1.2の時の命令(mruby 1系)ではなく現行のmruby 3系の命令に合わせているので、サポート済みの命令が完全に一致しているわけではない。

内部実装についてもう少し言及すると、去年の段階では雰囲気でやっていたのを、 mruby/c のC実装を参照しながらなるべく忠実? にRustに置き換えた*1リポジトリにはmruby/cのライセンスファイルも同梱してある。

mruby/c 1.2 で何ができるかは、以下のQiita記事を読めば雰囲気が掴める。

qiita.com

そう、そもそも mruby/c 1.2 の時点ではブロックも、例外もサポートしていないのだ...。なので堂々と後回しに...。

とはいえ、それでもまだまだ標準ライブラリ、preludeを全然実装していないので、これから地道にやろうかな...。という感じ。だいぶやったな! ってなったらRCを外します。例外は去年kateiさんに何か言われたので早めに向き合っちゃおうかな...。

ちなみにVMを置き換えた結果、わずかに fib() が速くなった*2 *3。書き換え時に、レジスタにHashMapを使うのをやめたりはしていたが、そういうのが効いたとかじゃないと思うが...まあ、遅くなってなくて良かった。

$ time wasmtime --invoke fib fib.wasm 30           
warning: using `--invoke` with a function that takes arguments is experimental and may break in the future
warning: using `--invoke` with a function that returns values is experimental and may break in the future
832040
wasmtime --invoke fib fib.wasm 30  2.49s user 0.01s system 99% cpu 2.504 total

$ time wasmtime --invoke fib fib-1.0.0-rc2.wasm 30 
warning: using `--invoke` with a function that takes arguments is experimental and may break in the future
warning: using `--invoke` with a function that returns values is experimental and may break in the future
832040
wasmtime --invoke fib fib-1.0.0-rc2.wasm 30  1.99s user 0.01s system 99% cpu 2.007 total

ちゃんとしたチューニングは機能が揃ってからにしますが...。Rcとか大量利用してるしきっと何かありそう。


RubyKaigi 2024 の時の実装に比べて、Rubyっぽいコードがかなり動くようになっていると思うので、ぜひお試しください。ちなみにimport/exportの仕様は変えていない。

*1:しかしまあさらに雰囲気で誤魔化した箇所も多々

*2:環境は MacBook Pro M3 です

*3:よく見たら実行時間80%とかになるので割とちゃんと速くなってるな...