WebAssemblyを試してみた


なにこれ

名前そのままブラウザからアセンブリを実行できるようにする技術であり、高速化手段、あるいはJavaScriptの処理系にできないことをするといった目的で提案された。

現在多くのブラウザでサポートされているasm.jsとの違いは、JavaScriptのサブセットであるためにロードタイムに課題があったasm.jsに対し、WebAssemblyでは直接バイナリを読み込むことでこの問題を解決している。

現在、Chrome(Canary)に実装され、簡単に試すことができるようになった。

試したよ

参考にした記事

つかうもの

Google Chrome Canary

WebAssemblyを使うには chrome://flags/#enable-webassembly にチェックをつけて有効化する。

llvm

-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssemblyを付けてcmakeする。

brew経由でインストールする場合にはbrew edit llvmで追加。

clang

Macに標準で入ってるclangではうまくいかなかったのでclang-3.8を使った。おそらくbrew install llvm38 --with-clangのものだと思う。

binaryen

https://github.com/WebAssembly/binaryen

クローンしてきてビルド&インストール

sexpr-wasm-prototype

https://github.com/WebAssembly/sexpr-wasm-prototype

クローンしてきてビルド&インストール

(クローンしたあとgit submodule update --init忘れずに)

変換してみる

変換はこんな感じの流れ

C/C++ -> LLVM bitecode -> Assembly -> S-expression -> binary

今回はC++のコードを変換する。

sample.cpp
extern "C" {
  int fib(int n) {
    int i, t, a = 0, b = 1;
    for (i = 0; i < n; i++) {
      t = a + b; a = b; b = t;
    }
    return b;
  }
}

C++の場合、関数名がmanglingされてしまうので、回避するためにextern "C" {}をしてる。

1. まずC++からLLVMバイトコードに変換
clang++-3.8 sample.cpp -emit-llvm --target=wasm32 -Oz -c -o sample.bc
2. LLVMバイトコードからアセンブリに変換
llc sample.bc -march=wasm32 -filetype=asm -o sample.s
3. アセンブリからS式に変換
s2wasm sample.s > sample.wast
4. S式からWebAssemblyバイナリに変換
sexpr-wasm sample.wast -o sample.wasm

これで読み込むための.wasmができあがる。

前述の参考にした記事ではLLVM IR形式(.ll)に変換してからアセンブリに変換していた。この方法でも同様の結果が得られる。

実行してみる

jsはこんな感じ

index.js
var xhr = new XMLHttpRequest();
xhr.open('GET', 'sample.wasm', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
  var binary = xhr.response;
  var binarray = new Uint8Array(binary);
  var module = Wasm.instantiateModule(binarray);
  console.log(module.exports);
  var fib = module.exports.fib;
  var arr = [];
  for (var i = 0; i < 20; i++) {
    arr.push(fib(i));
  }
  console.log(arr);
};
xhr.send(null);

出来上がったバイナリをXHRで取ってきてUint8Arrayに変換してWasm.instantiateModuleに投げると、オブジェクトが返ってくる。

返ってきたオブジェクトのexportsの中にC++で定義した関数が入っているのでそのまま引数を渡してアクセスできる。

今回は20個のフィボナッチ数列を表示するだけ。

原因がわからないのだが、clangでのビルドで最適化を切るとWebAssemblyのバイナリはできるが、実行するとエラーが出てしまった。いつか解決したい。

WebのフロントエンドにC/C++のコードが介入してくると考えるとフレームワークやライブラリのパラダイムも変わってくるのかもしれない。

いま熱くなってきているWebAssemblyだが、まだ情報は少ないため、再び試す機会があればやってみようと思う。

今回のコードはgithubにポイしておいた。

https://github.com/pnlybubbles-gomibako/wasm-sample