うなすけとあれこれ

2021年02月14日

RubyとWebAssemblyの関係についてわかる範囲でまとめる

Artichoke

はじめに

2021年1月にv1.0がリリースされたWasmerにRuby Gemが存在することに触発されて調べてみました。RubyとWebAssemblyが関わっているものについてわかる範囲でまとめ、軽くどのようなものかを書いていきます。

僕自身、業務はおろかプライベートでもWASMを書いたことはなく浅い理解しかしていないですが……

WebAssembly (WASM)とは

WebAssembly は最近のウェブブラウザーで動作し、新たな機能と大幅なパフォーマンス向上を提供する新しい種類のコードです。基本的に直接記述ではなく、C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。

この機能はウェブプラットフォームにとって大きな意味を持ちます。 — ウェブ上で動作するクライアントアプリで従来は実現できなかった、ネイティブ水準の速度で複数の言語で記述されたコードをウェブ上で動作させる方法を提供します。 https://developer.mozilla.org/ja/docs/WebAssembly/Concepts

なんか、そういうやつです。

Ruby to WASM

Rubyを何らかの方法で最終的にWASM Bytecodeにコンパイルするものたちです。

blacktm/ruby-wasm

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

Rlang

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

prism-rb/prism

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にコンパイルされて実行されるようです。

Ruby on WASM

WASM上でRubyを実行できるようにするものたちです。

Artichoke

https://www.artichokeruby.org

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が動いている様子を観測できます。

Artichoke

runrb.io

ruby/rubyをEmscriptenで動かしているようです。もっと詳しく説明すると、独自patchを適用したRuby 2.6からEmscripten(emmake)でminirubyのbytecodeを生成しています。それをさらにEmscripten(emcc)でWASMにコンパイルしています。ここから先がちょっとよくわからなかったのですが、最終的にRubyをWASM bytecodeにしているのでしょうか?

https://github.com/jasoncharnes/run.rb/blob/d0f5cf9c954335795fca7c24760e728dbf47b425/src/emscripten/ruby-2.6.1/Dockerfile

PlaygroundでRubyを実行する度にworkerが生成されて別のbytecodeを実行しているようなのですが……RUBY_PLATFORMx86_64-linuxRUBY_VERSION2.6.1となっていました。Encoding.listの結果が少なかった1から実際に動いているのはminirubyなのかもしれません。

runrb.io

wruby

https://github.com/pannous/wruby

minirubyをEmscriptenでWASMにコンパイルしています。なんとmruby/mrubyをforkしています。

https://github.com/mruby/mruby/compare/master…pannous:master

mwc

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

mruby-L1VM

https://github.com/taisukef/mruby-L1VM

BASICが動く教育向け(でいいのか?)マイコンボードのIchigoJam上で動くmruby実装をWebAssemblyに移植したものです。mruby_l1vm.hがキモのようですね。

mruby on web - WebAssemblyのバイナリ4KB以下で動かす超軽量クライアントサイド用Ruby #ruby / 福野泰介の一日一創 / Create every day by Taisuke Fukuno

emruby

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って、凄いですね。

WASM runs by Ruby

RubyからWASMを実行できるようにするものです。

wasmer.io

冒頭で紹介したものです。Wasmerは、WebAssemblyをWebブラウザ外で実行できるランタイムです。wasmer gemはそのWasmerをRubyから扱えるようにするgemとなっており、以下のドキュメントから具体的な使い方を知ることができます。

https://www.rubydoc.info/gems/wasmer/

上記ドキュメントにあるように、例えばRustのコードをWASMにコンパイルしてRubyから実行する、ということができますね。

wasmtime-ruby

https://github.com/dtcristo/wasmtime-ruby

WasmtimeのRuby bindingとあります。Wasmtimeは、(Wasmerのように)あらゆるプラットフォームでのWASMの実行を可能にすることなどを目指すBytecode Allianceのプロジェクトのひとつで、WASM及びWASIの軽量ランタイムです。

require 'wasmtime/require' とすることで、WASMバイナリ及びテキスト表現を直接 requireして実行できるのは面白いですね。

WASM.rb

https://github.com/technohippy/wasmrb

Wasmerとは異なり、pure rubyのWASM処理系です。(languageで半数以上がWASMになっていますが、これはtest dir以下に含まれているものっぽい) また、WASM binaryをRubyのhashっぽくinspectしてくれる機能もあります。

TODO.md を見る限りではまだ未実装の仕様も多いですが、WASMの勉強には(まだ)コードの量も少なく勉強するのには良さそうです。

WASM to Ruby

WASMをRubyのコードに変換するものです。(逆アセンブル?)

edvakf/wagyu

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は使用されていなかったものです。

webruby

https://github.com/xxuejie/webruby

Rubyではなくmrubyではありますが、Web上でruby scriptを実行できるようにするものです。 http://joshnuss.github.io/mruby-web-irb/ から実際に試すことができます。

これはEmscriptenによってmrubyをJavaScriptに変換しているのみで、WASMは使用されていませんでした。

DXOpal

まず、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されてはいないようでした。

追記

2021-02-18

emrubyについての記述を追加しました。

2021-02-22

「その他」を追加しました。

2021-04-13

WASM.rbについての記述を追加しました。

2021-07-28

誤字を修正しました。


  1. https://naruse.hateblo.jp/entry/20110118/1295345908 より 

Tweet
2021年02月14日