2021年1月にv1.0がリリースされたWasmerにRuby Gemが存在することに触発されて調べてみました。RubyとWebAssemblyが関わっているものについてわかる範囲でまとめ、軽くどのようなものかを書いていきます。
僕自身、業務はおろかプライベートでもWASMを書いたことはなく浅い理解しかしていないですが……
WebAssembly は最近のウェブブラウザーで動作し、新たな機能と大幅なパフォーマンス向上を提供する新しい種類のコードです。基本的に直接記述ではなく、C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。
この機能はウェブプラットフォームにとって大きな意味を持ちます。 — ウェブ上で動作するクライアントアプリで従来は実現できなかった、ネイティブ水準の速度で複数の言語で記述されたコードをウェブ上で動作させる方法を提供します。 https://developer.mozilla.org/ja/docs/WebAssembly/Concepts
なんか、そういうやつです。
Rubyを何らかの方法で最終的にWASM Bytecodeにコンパイルするものたちです。
https://github.com/blacktm/ruby-wasm
紹介記事がTechRachoさんによって日本語訳されたので見覚えのある方もいるかと思います。
記事内に言及がありますが、以下のようにmrubyを経由して最終的にWASM binaryを生成します。
Ruby script → MRuby bytecode → C → emcc (Emscripten Compiler Frontend) → LLVM → Binaryen → WebAssembly
ここで登場するbinaryenですが、GitHubのWebAssembly org以下で開発されている、公式のtoolchainです。上記で行われているようなWebAssemblyへのコンパイルの他にも、wasm bytecodeからのunassemble(text formatへの変換)などの様々なツールが同梱されています。
https://github.com/WebAssembly/binaryen
https://github.com/ljulliar/rlang
a Ruby-like language compiled to WebAssembly
Rubyのsubsetである “Rlang” からWASM bytecodeへのコンパイルを行うものです。このRlangとRubyの差異は以下にまとまっています。例えば整数型のサイズを32bitか64bitかを指定するsyntaxや、可変長引数が使用できないなどの違いがあります。
https://github.com/ljulliar/rlang/blob/master/docs/RlangManual.md
名前の由来として、C言語に変換できるSmalltalkのsubsetであるSlangからもじって付けられているようです。(そういう意味でRと名前が被っているのは仕方がないとも述べられています)
http://wiki.squeak.org/squeak/slang
https://github.com/prism-rb/prism
Build frontend web apps with Ruby and WebAssembly
frontend web applicationをRubyとWebAssemblyで作成できるようにするframeworkです。Prism::Component
から継承したClassに記述されたapplication logicがEmscriptenによりWAMにコンパイルされて実行されるようです。
WASM上でRubyを実行できるようにするものたちです。
Bundle Ruby applications into a single Wasm executable with Artichoke, a Ruby made with Rust.
Rust実装によるRuby runtimeです。Ruby界隈ではArtichokeの名前を聞いたことのある方は多いと思います。RustはコードをWASMにコンパイルすることができるので、ArtichokeもWASMとして動かすことができます。 https://artichoke.run がPlaygroundなのですが、inspectorからWASMが動いている様子を観測できます。
ruby/rubyをEmscriptenで動かしているようです。もっと詳しく説明すると、独自patchを適用したRuby 2.6からEmscripten(emmake)でminirubyのbytecodeを生成しています。それをさらにEmscripten(emcc)でWASMにコンパイルしています。ここから先がちょっとよくわからなかったのですが、最終的にRubyをWASM bytecodeにしているのでしょうか?
PlaygroundでRubyを実行する度にworkerが生成されて別のbytecodeを実行しているようなのですが……RUBY_PLATFORM
は x86_64-linux
、RUBY_VERSION
は 2.6.1
となっていました。Encoding.list
の結果が少なかった1から実際に動いているのはminirubyなのかもしれません。
https://github.com/pannous/wruby
minirubyをEmscriptenでWASMにコンパイルしています。なんとmruby/mrubyをforkしています。
https://github.com/mruby/mruby/compare/master…pannous:master
https://github.com/elct9620/mwc
The tool for the developer to help them create mruby applications on the WebAssembly.
とのことですが、READMEからはイマイチどういうものかつかめなかったので、Create Project
に記載のあるmwc init
が何をするか見てみたところ、<mruby.h>
をincludeしてmrubyの機能を使用するC言語のコードをEmscriptenによりWASMへとコンパイルしているようでした。
https://github.com/elct9620/mwc/tree/master/lib/mwc/templates/app
https://github.com/taisukef/mruby-L1VM
BASICが動く教育向け(でいいのか?)マイコンボードのIchigoJam上で動くmruby実装をWebAssemblyに移植したものです。mruby_l1vm.h
がキモのようですね。
https://github.com/mame/emruby
作り込みはぜんぜんダメですが、仲間にいれてあげてください! 最近の ruby/ruby master を emscripten できるようにしてますhttps://t.co/7PvkHsZ0In
— Yusuke Endoh (@mametter) February 18, 2021
作者のmameさんから直接教えていただきました。 ruby/rubyにpatchを当てたものをEmscriptenによってWASMにコンパイルしています。(WASMにしているのはminiruby) https://mame.github.io/emruby/ で試すこともできます。最近作成されていることもあり、Rubyのversionが3.1.0devなのが凄いですね。
読み方は「いーえむるびー」であり、「えむるびー」ではないのに注意。この40行ほどのpatchでWASMにコンパイルできるんですね……
ありがとうございます!patch は、文字列を JS eval する emscripten API を生やすだけなので、なくてもコンパイルできるはずです
— Yusuke Endoh (@mametter) February 18, 2021
Emscriptenって、凄いですね。
2022年1月19日に、kateinoigakukunさんによってCRubyのplatformとしてWASIを対象としたコンパイルができるようになりました。kateinoigakukunさんは1月14日にMatzのapproveによってRuby commiterになられています。すごい……
これは2021年度Rubyアソシエーション開発助成によって支援されている取り組みでもあります。
2021年度Rubyアソシエーション開発助成金 公募結果発表
RubyプログラムをWebAssemblyバイナリにパッケージ化し、1バイナリでの配布を可能にすることも目指す
ともあります。とても期待が高まりますね。
実際にどういう風に試せるかについては、公式のドキュメント及びznzさんの記事が参考になります。
RubyからWASMを実行できるようにするものです。
冒頭で紹介したものです。Wasmerは、WebAssemblyをWebブラウザ外で実行できるランタイムです。wasmer gemはそのWasmerをRubyから扱えるようにするgemとなっており、以下のドキュメントから具体的な使い方を知ることができます。
https://www.rubydoc.info/gems/wasmer/
上記ドキュメントにあるように、例えばRustのコードをWASMにコンパイルしてRubyから実行する、ということができますね。
https://github.com/dtcristo/wasmtime-ruby
WasmtimeのRuby bindingとあります。Wasmtimeは、(Wasmerのように)あらゆるプラットフォームでのWASMの実行を可能にすることなどを目指すBytecode Allianceのプロジェクトのひとつで、WASM及びWASIの軽量ランタイムです。
require 'wasmtime/require'
とすることで、WASMバイナリ及びテキスト表現を直接 require
して実行できるのは面白いですね。
https://github.com/technohippy/wasmrb
Wasmerとは異なり、pure rubyのWASM処理系です。(languageで半数以上がWASMになっていますが、これはtest dir以下に含まれているものっぽい) また、WASM binaryをRubyのhashっぽくinspectしてくれる機能もあります。
TODO.md を見る限りではまだ未実装の仕様も多いですが、WASMの勉強には(まだ)コードの量も少なく勉強するのには良さそうです。
WASMをRubyのコードに変換するものです。(逆アセンブル?)
https://github.com/edvakf/wagyu
READMEには
Wagyu aims to be a library to parse and execute Web Assembly binaries on Ruby.
と書かれていますが、2019年に行われたTama Ruby会議の発表によると、WASMのテキスト表現を一度Rubyのコードへ変換してから実行するようなアプローチになっています。
WebAssemblyを Rubyにコンパイルする 黒魔術コード完全解説 - Speaker Deck
「こんなものもありますよ」と教えていただいたものの、現時点でWASMは使用されていなかったものです。
https://github.com/xxuejie/webruby
Rubyではなくmrubyではありますが、Web上でruby scriptを実行できるようにするものです。 http://joshnuss.github.io/mruby-web-irb/ から実際に試すことができます。
これはEmscriptenによってmrubyをJavaScriptに変換しているのみで、WASMは使用されていませんでした。
まず、RubyのコードをJavaScriptに変換するOpalというコンパイラがあります。例えばRuby公式Webサイトからリンクされている、Webブラウザ上でRubyを試すことのできる https://try.ruby-lang.org ではOpalが使われています。
そして、RubyからDirextXのAPIを利用することができ、RubyによってWindows向けにゲームを開発することのできるライブラリ、DXRubyというものがあります。
DXOpalは、そのDXRubyのAPIを「だいたいそのまま」移植してWebブラウザ上でゲームを開発できるようにしたライブラリです。
そのDXOpalですが、RubyKaigi 2017にて一部をWebAssmeblyにしてみたとの発表がありました。
Ruby, Opal and WebAssembly - Speaker Deck
発表では、RubyをWebAssemblyに移植する難しさについても言及されています。
しかし発表内でデモされていたWebAssembly実装ですが、現時点ではmasterにmergeされてはいないようでした。
emrubyについての記述を追加しました。
「その他」を追加しました。
WASM.rbについての記述を追加しました。
誤字を修正しました。
Ruby本体についての記述を追加しました。