飽きっぽい人のブログ

プログラマとしてもテスターとしても中途半端な人のブログ

WebAssemblyのAOTコンパイラを作った

本記事はWebAssembly Advent Calendar 2018の26日目の記事である。
Advent Calendarに間に合わなかったけど、何も書かないのはもったいないので書くことにする。

概要

WebAssembly AssemblyをAOTでコンパイルするコンパイラを作った。
これによりブラウザを使わなくてもWebAssemblyを実行できる。(もちろんNode.js等も不要)

作った目的

WebAssemblyには期待しているが、ネットで見かける話題ではブラウザ上でのマイニングとか、ブラウザゲームが軽くなると言った話が多かったのでそれ以外の道を示したかった。あと前々から低レイヤには興味があったが手を出してなかったのでやってみたかったというのもある。

その名前のせいかWebAssemblyはブラウザでしか動かないと思っている人が多く悲しい。確かに実用的なアプリケーションを作ろうとすると現状ブラウザに限定されてしまうのは事実だ。
しかしWebAssemblyの規格にはブラウザで実行するように制限するようなことは自分が読んだ限りでは書いてなかったし、公式のドキュメントにはIoTやデスクトップアプリといった環境でも実行できるように設計していると書いてある。
実際すでにWebAssemblyをring0で実行できるOS洗濯機でWebAssemblyを実行できるようにするプロジェクトが存在している。WebAssemblyの可能性はまだまだ広がっていくだろう。

作り方

まず規格を読みます。
次に規格で求められている通りにランタイムシステムとWebAssemblyの命令をLLVMで実装します。
最後にコンパイルする対象のWebAssemblyがimportしている関数で足りないものがあれば、ランタイム側で提供してあげます。
簡単ですね。

嘘です。クソ難しかったです。8ヶ月ぐらいかかった。
LLVMAPIドキュメントに関数の説明が何も説明が書いていないのが一番つらかった。普段言語作ってる人たちはどうしてるんだろう。
WebAssemblyの規格でもExecutionの項がAOT実装者向けに書いてあるわけではなくて脳内解釈してやる必要があった。

これは実用的なの?

現状muslと一緒に吐かれたwasmファイルでHello worldするのが精一杯なので全く実用的じゃない。
rustだとターゲットをwasmにするとprintln!で実際に出力されるコードが吐かれないようなのでHello worldできなかった。
最も頑張ってimportされてる関数を実装していけばある程度のことはできるようになるとは思うが、当然importして依存している各wasmファイルで全然違うので、現実的とは言えない。

この問題を解決するにはWebAssembly用のライブラリのようなものを規格化する必要があると思う。
できればブラウザに依存しない部分のライブラリと各ブラウザで共通のライブラリは分けて規格化されてほしいが、そもそもライブラリの規格化は話に出ているのだろうか?

まとめ

実際にWebAssembly処理系を実装してみたが更に関わっていきたいという気持ちが強くなった。
将来的にはWebAssemblyの規格の仕様策定に参加していきたいが、そのためには覚えなければ行けないことがたくさんありそう。

ソースコード