セカイノカタチ

世界のカタチを探求するブログ。関数型言語に興味があり、HaskellやScalaを勉強中。最近はカメラの話題も多め

FirefoxにWebAssemblyが搭載されたらしいので試してみた

Firefox、ゲームなどをネイティブ並に高速実行する「WebAssembly」を採用 - PC Watch

こんな感じで、PC系のニュースサイトで話題になっているので試してみた。

WebAssembly とは、ブラウザ上でバイトコードを実行できるようにする標準規格で、今まで実質的にJavaScript一択だったブラウザ上のプログラム実行環境を拡張するものとして、とても期待している。

qiita.com

とりえあえず、「WebAssembly」でググると一番上に出てくるこの記事を参考に、公式サイトっぽいところを覗いてみる。

Developer’s Guide - WebAssembly

WebAssembly のコンパイラをインストールして、C言語のサンプルコードを走らせるガイドになっていた。

Windows, MacOS, Linuxがサポートされているようで、Windowsのサポートがおもったより手厚いのは、マイクロソフトの支援が入っているからかな?

Windows上でビルドするのは心許ないので、VM上のLinuxでビルドしてみることに。

とりあえず、下記の環境が必要とのことなので揃える。

  • CMake
  • gcc
  • python(2.7.x)

コマンド実行。

$ sudo apt-get install -y build-essential cmake

phtyonは、もとから2.7系が入っていたので準備オッケー。

$ git clone https://github.com/juj/emsdk.git
$ cd emsdk
$ ./emsdk install sdk-incoming-64bit binaryen-master-64bit
$ ./emsdk activate sdk-incoming-64bit binaryen-master-64bit
$ source ./emsdk_env.sh

ほぼおまじない通りに実行すれば環境が整う。

ただし、VMにメモリを4GB割り当ててたんだけど、足りなくてリンカが落ちた。8GBにしたら通ったので、メモリは多めに積んでおきたい。

$ mkdir hello
$ cd hello
$ echo '#include <stdio.h>' > hello.c
$ echo 'int main(int argc, char ** argv) {' >> hello.c
$ echo 'printf("Hello, world!\n");' >> hello.c
$ echo '}' >> hello.c
$ emcc hello.c -s WASM=1 -o hello.html

サンプルコードのコンパイルもおまじない通り。

組み込みのhttpサーバーを立ち上げれば、実行される様子を見ることができる。

$ emrun --no_browser --port 8080 .

これは、単なるhttpサーバーっぽいので、apacheやnginx、http-serverなど好きなものを使ってOKっぽい。

一応スクショを貼っておくけど、実際 WebAssembly が動いているところは、「Hello, world!」と表示されている部分のみ。それ以外の部分は、コンパイラが吐くhtmlで描画されている。はっきり行って、htmlコードもゴテゴテしていて、どの部分が WebAssemblyに最低限必要なコードなのか全く不明。^^;

f:id:qtamaki:20170309144650p:plain

先のコンパイラでは、出力ファイルに「hello.html」を指定しているが、実際には、「hello.html, hello.js, hello.wasm」の3つのファイルが出力されていて、核心となるのは、hello.wasmのみ。

htmlとjsは、実行画面をそれっぽく見せるためのスタブだ。

これだけだと、本当にWebAssemblyが実行されているのかわかりにくいので、最初の記事で例示されていたデモサイトの動作も確認してみた。

https://1984weed.github.io/webassembly-sample/src/nqueen/

Firefox 51.0.1でアクセスすると、このようにWebAssemblyオブジェクトが見つからないというエラーが、コンソールに出て「Wasm execute」ボタンが機能しない。

f:id:qtamaki:20170309145341p:plain

Firefox 52ならば、そのようなエラーは出ないし、「Wasm execute」が実行できるのでちゃんと動いているようだ。

f:id:qtamaki:20170309145404p:plain

WebAssemblyをサポートしてるかどうかは、「WebAssembley」オブジェクトの有無で確認できるってことみたいだ。

そして、このデモサイトは、ChromeのCanary版を想定して書かれたようなので、クロスブラウザで動作していると言うことも確認できた。流石は標準規格。

動作方法について端的に説明すると、上記のようにソースコードをコンパイルしてバイトコードを作ったら、WebAssemblyオブジェクトを利用して、下記のようにコンパイル→インスタンス化すれば良いらしい。

function instantiate(bytes, imports) {
  return WebAssembly.compile(bytes).then(m => new WebAssembly.Instance(m, imports));
}

あとは、バイトコードをXHRやfetchAPIで取得して、バイト列を取り出してこの関数に食わしてやればよい。importObjectは、バイトコードに渡す引数だか変数だかになる。

fetch('simple.wasm').then(response => response.arrayBuffer())
  .then(bytes => instantiate(bytes, importObject))
  .then(instance => instance.exports.e());

あと、メモリの管理は、バイトコード側でしなければならなくて、めんどくさそうだ。

var memory = new WebAssembly.Memory({initial:10, maximum:100});

とりあえず、今日のところはこんな感じで、概要はつかめた感じがするのでここまで。