Rust
Emscripten
WebAssembly
AssemblyScript

ご挨拶

この記事は ピクシブ株式会社 Advent Calendar 2017 8日目の記事です。

今年の7月からピクシブの福岡オフィスでアルバイトをしています。@printf_moriken です。
JavaScript が得意でフロントエンドの領域ばかりやっていたのですが、ピクシブでバイトするにあたって Android と iOS アプリの開発もやり始めました。

好きな IEEE は IEEE 754-2008 です。個人的に JavaScript に半精度浮動小数点数を入れようと活動しています1。Stage 1 です。よろしくお願いします。

WebAssembly について

WebAssembly はブラウザでバイナリを実行できるようにするための技術、ファイル形式のことを言います。
旧来の技術に asm.js がありますが、バイナリ化したことによって以下のような利点があります。

  • バイナリ化することによるファイル容量(通信量)の削減
  • asm.js と比べてコンパイル時のバリデーションのコストが遥かに小さい(速い)

一方で以下のようなデメリットもあります。

  • JavaScript にはバイナリを直接埋め込むことが出来ないため、XMLHttpRequest や Fetch API が必要

asm.js は Javacript のコード中に "use asm"; 宣言をした特別な函数を埋め込む設計になっている一方で、WebAssembly では一応 Uint8Array でバイナリ配列を埋め込むようなことは出来ますがテキストなので非効率的です23

WebAssembly の基本的なことについて詳しく知りたい方は @tkihira さんの以下の記事が勉強になります。
WebAssembly の基礎

また今年の Advent Calendar にどしどし投稿されているみたいですので、興味のある方はそちらで最新情報を得てはいかがでしょうか。
WebAssembly Advent Calendar 2017

Emscripten について

Emscripten は C/C++ を LLVM を経由して asm.js に変換し、それを含んだ JavaScript を生成するツールです。

また Binaryen を使うことで asm.js の部分を WebAssembly に変換することが出来ますが、いずれにせよ JavaScript によってラップされる形で出力されます4

実験的機能に JavaScript にラップされないスタンドアロンビルドがあります5が、まだ安定していないのと、標準ライブラリを自前で用意しないといけない設計でなかなか実用には厳しいです。

WebAssembly のスタンドアロンビルド(脱!Emscripten)

Emscripten では JavaScript でラップされる形となってしまいますが、WebAssembly のバイナリ単体で得たいところです。利点としては以下の通り。

  • ブラウザにコンパイル後のキャッシュを持たせられる6
  • WebAssembly と JavaScript の相互のやり取りが容易になる
  • Emscripten のラッパーの JavaScript が WebAssembly のパスを持つ……みたいなことをしなくてすむ7
  • 気分的に良い✨

WebAssembly をビルドする方法については現在色々なアプローチがあり、 Emscripten Night #5 での @chikoski さんの資料にわかりやすくまとまっています。
https://speakerdeck.com/chikoski/20171018-wasm?slide=9

ここでは以下のツール、言語について軽く触れようと思います。

  • AssemblyScript
  • dcodeIO/webassembly
  • LLVM/Clang
  • Rust

AssemblyScript

AssemblyScript は TypeScript のサブセットです。malloc, free 系も用意してあり、大体のコードは書くことができそうです。

@chikoski さんの記事に使用例が載っています。
AssemblyScriptを使ってTypeScriptのコードを早くしよう

dcodeIO/webassembly

dcodeIO/webassembly は WebAssembly 用に C の標準ライブラリを用意してコンパイルするツールの他、Node.js で WebAssembly が使える環境を提供してくれます。C で書かれた資源を WebAssembly で使えるようにするにはこちらを選ぶと良さそうです8

@ukyo さんの記事に使用例が載っています。
dcodeIO/webassembly内のツールチェーンでzlibをビルドしてみる

LLVM/Clang

直接 C/C++ を WebAssembly にビルドする方法です。標準ライブラリを自前で用意する必要が有るため、C を使う場合だと前述の dcodeIO/webassembly を使ったほうがよさそうです。

具体的には musl, libcxx のヘッダーファイルを読み込みつつも、実体の函数やクラスは WebAssembly 向けではないため clang には食わせないみたいなことをする必要があります。そして吐き出された WebAssembly を使う時には足りないそれらの函数を JavaScript で補って、WebAssembly の import に食わせるみたいな中々ハッキ―なことをしないといけません9

Rust

Rust は Mozilla が開発しているプログラミング言語です。もともと Emscripten を経由して WebAssembly にビルドできる言語でしたが、最近直接 LLVM の wasm32-unknown-unknown target にビルドできるようになったみたいです10

Rust 自体は rust-bindgen を使うことで C/C++ の資源を使うことが出来るみたいですが、あくまでこれは FFI を生成するツールなので、WebAssembly のビルドに活かすのは厳しそうです。

@bokuweb さんの記事に使用例が載っています。
Rust + WebAssembly でpngデコードを行うnode_moduleを作ってみる

個人的な見解

現状だと完全にゼロから WebAssembly を出力したい場合は AssemblyScript を使い、C の資源を使いたい場合は dcodeIO/webassembly を使えばよさそうです。そして腕に自身はある人は Rust を使う。

個人的に vorbis を WebAssembly でデコードしたいのですが、libvorbis が依存している stdio.h 系の一部の函数が dcodeIO/webassembly では使えないみたいなのでなかなか厳しいです……と思っていたら lewton というものを見つけてしまったので、これから Rust を勉強しようかなと思います😂

おわりに

WebAssembly のビルドツールが出揃ってきていよいよ本格的に使えるようになってきましたね! みなさんも Rust を勉強して WebAssembly をプロダクトに投入していきましょう!

本来なら Rust から WebAssembly を生成する例をここに書く予定でしたが、一週間弱で Rust を習得することができませんでした。

明日は SpiderMonkey に pipeline operator を実装したすごいエンジニアの @hakatashi です。引き続き ピクシブ株式会社 Advent Calendar 2017 をお楽しみください。


  1. https://qiita.com/printf_moriken/items/1a16d759cefea1b3210e 

  2. data URL を使ったほうが比較的効率的かな。 

  3. ECMAScript Stage 1 で Binary AST が議論されており、もしかしたらそのままバイナリを埋め込める日が来るかもしれません☺ 

  4. ラップする JavaScript はこちら。 

  5. https://github.com/kripken/emscripten/wiki/WebAssembly-Standalone 

  6. WebAssembly Advent Calendar 2017 3日目の記事 巨大 WebAssembly ファイルのコンパイル時間にも記載されていますが、IndexedDBWebAssembly.Module を保存できます。残念ながら廃止されてしまいました。 

  7. Emscripten を使った場合、ビルドした WebAssembly のバイナリのディレクトリを移動するとラッパーの JavaScript から参照できなくなり辛い目に合う……。 

  8. 使える標準ライブラリの函数はこちらに書いてあります。 

  9. 今は有料ですが、こちらの動画が勉強になりました。 

  10. https://www.hellorust.com/news/native-wasm-target.html