<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>清水智公 &#8211; HTML5Experts.jp</title>
	<atom:link href="/chikoski/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>Webブラウザで高速な演算を可能にする低水準言語asm.jsと、WebAssembly詳解ーasm.jsを高速に動作させる新しいコンパイラーターゲットWASMとは？</title>
		<link>/chikoski/22523/</link>
		<pubDate>Tue, 28 Mar 2017 02:00:49 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=22523</guid>
		<description><![CDATA[連載： 低水準言語asm.jsとWebAssembly詳解 (4)低水準言語asm.jsとWebAssembly詳解の第4回目です。前回までで、asm.jsの必要とされる理由と、その仕様、そしてasm.jsを生成するツー...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/asmjs/" class="series-384" title="低水準言語asm.jsとWebAssembly詳解" data-wpel-link="internal">低水準言語asm.jsとWebAssembly詳解</a> (4)</div><p><a href="https://html5experts.jp/series/asmjs/" data-wpel-link="internal">低水準言語asm.jsとWebAssembly詳解</a>の第4回目です。前回までで、asm.jsの必要とされる理由と、その仕様、そしてasm.jsを生成するツールであるEmscriptenを紹介しました。CやC++で書かれたソースコードから「低水準」なJavaScriptコードが出力され、それが高速に動作する理由について述べてきました。</p>

<p>前回の最後で述べた通り、Emscriptenで出力されたasm.jsのファイルはサイズが大きくなりがちでした。ファイルのサイズが大きくなるとダウンロードに時間がかかるのはもちろん、ネイティブコードへのコンパイルにも大きく時間がかかってしまいます。つまり高速に動作するのは良いが、起動に時間がかかるサイトができてしまうことになります。</p>

<p>この問題を解決するために登場するのがWebAssembly(WASM)です。これはプログラミング言語ではなく、ファイルフォーマットの一種です。
同じプログラムをasm.jsとして出力したものと、WASMとして出力したものを比較すると、WASMの方がぐっと小さくなっていることがわかります。</p>

<table>
<thead>
<tr>
  <th>プログラム</th>
  <th>コードのサイズ（asm.js）</th>
  <th>コードのサイズ（WebAssembly）</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Hello World</td>
  <td>301KiB</td>
  <td>204KiB</td>
</tr>
<tr>
  <td>AngryBots</td>
  <td>19MiB</td>
  <td>6MiB</td>
</tr>
<tr>
  <td>StandardAssets</td>
  <td>25.7MiB</td>
  <td>13.4MiB</td>
</tr>
<tr>
  <td>UnityChan-CRS</td>
  <td>21.3MiB</td>
  <td>11.4MiB</td>
</tr>
</tbody>
</table>

<p>現在はその仕様策定が固まり、ブラウザへの実装も済み、リリースを待つばかりです。またコンパイラへの実装も進んでいます。特にBinaryen（後述します）への最適化処理の実装のおかげで、asm.jsより高速に実行できるようになりました。</p>

<p>下記のグラフ（<a href="https://hacks.mozilla.org/2016/10/webassembly-browser-preview/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MozillaのHacksブログ</a>より引用）はasm.jsとWASMの速度を比較したものです。値はネイティブの実行スピードに対する相対的な速度を表していて、1に近づけは近づくほどネイティブに近いスピードで動いていることを表しています。Bulletを除く全てのベンチマークでasm.jsより高速に動いています。これはコンパイラの行う最適化処理のおかげです。</p>

<p><img src="/wp-content/uploads/2017/03/asmjs-wasm-comparison-updated-300x199.png" alt="asm.jsとWebAssemblyの速度比較" width="300" height="195" class="aligncenter size-medium wp-image-22524" /></p>

<p>この評価は2016年10月末の時点に、Intel Core i7-2600 @ 3.40GHzで動作するLinux版 64-bit Firefox 52 (Nightly)で計測されました。現在は最適化処理の更なる修正によって、Bulletでもasm.jsを上回るパフォーマンスが出るようになっています。</p>

<p>連載の最後は、リリースが間近のWASMについて、コンパイル方法、仕様、そしてJavaScript APIについてご紹介します。</p>

<h2>WebAssemblyとは</h2>

<p>WebAssemblyとはプログラムを表すファイルフォーマットの一種で、拡張子には<code>.wasm</code>を利用することが一般的です。
Webで扱うファイルの大半はテキスト形式ですが、WASMはバイナリ形式でプログラムを表現します。
バイナリエディタを用いてWASMファイルを作成することも、もちろん可能ですが、Emscriptenに代表されるコンパイラを使って出力することが一般的です。</p>

<p>仕様は<a href="https://www.w3.org/community/webassembly/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">W3Cのコミュニティグループ</a>のメーリングリストや<a href="https://www.github.com/WebAssembly" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">GitHub</a>で議論が行われています。議論の指針は次の4つです。</p>

<ul>
<li>高速で効率的に実行できつつも、ポータブルであること</li>
<li>ソースを表示できること</li>
<li>安全であること</li>
<li>Webを破壊しないこと。つまり他のWeb技術と組み合わせることができること</li>
</ul>

<p>このコミュニティグループには、Google、Microsoft、Apple、そしてMozillaの各ブラウザベンダが参加しています。実装もそれぞれに進んでおり、Firefoxでは　52で、Chromeでは57でそれぞれ標準サポートされました。EdgeとWebkitは開発の途中です。<a href="https://blogs.windows.com/msedgedev/2016/03/15/previewing-webassembly-experiments/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Edgeの開発版でAngryBotsが動作している様子は、こちらの動画で確認できます</a>し、<a href="https://webkit.org/status/#specification-webassembly" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Webkitの状況はこちらで確認できます</a>。</p>

<h2>WASMの想定される利用例は？</h2>

<p>現在のところ想定されているWASMの利用方法は次の3パターンです：</p>

<ol>
<li>アプリ全てをWASMで実装する：C/C++で書かれたアプリをWebに移植するための手段</li>
<li>WASMでほとんどを実装し、UIなどをWeb技術で実装する</li>
<li>Webアプリケーションのうち、速度が必要な部分をWASMで実装する</li>
</ol>

<p>1はWebを新しいアーキテクチャとみなし、C/C++のソースコードをクロスコンパイルする、というイメージです。この典型例はゲームでしょう。iOSやAndroid、PS4、Xbox One、PCなど様々あるゲームプラットフォームにWebが加わり、いくつかのプラットフォームへゲームをリリースするのと同じようにWeb向けにゲームをリリースする、というイメージです。</p>

<p>2は既に持っているCやC++の資産を活かしつつ、リッチなUI/UXを提供するといった使い方です。例えば画像認識エンジンや、動画像処理エンジンをすでに持っていて、これらをサービス化したい、といった場合です。それらのエンジンをWASMに変換した上で、UXやUIはWebの技術や開発手法を利用して提供することで、お互いの良いところを取ることが可能です。</p>

<p>3は暗号や圧縮・展開、画像処理といった重たい処理の高速化にWASMを利用する、といった使い方です。asm.jsがよく使われてきた用法でもあります。サーバサイドであれば、Rubyが遅くなってきたのでRustで書き換える、Pythonでは辛いからGoで、といったことがよく行われてきました。フロントエンドではそのようなことは難しかったのですが、WASMを使うことで、アルゴリズムの改良などへ踏み込まずに高速化を行えるようになります。</p>

<h2>EmscriptenでWebAssemblyを出力するには</h2>

<p>テキスト形式のプログラムからWebAssemblyを変換して出力する方法は、概ね次の3つになります：</p>

<ol>
<li>C/C++で書かれたソースコードをEmscripntenで処理して出力する</li>
<li>Rustで書かれたソースコードをコンパイルして出力する</li>
<li>WAST（WASMのテキスト形式）で書き、それを変換して出力する</li>
</ol>

<p>現在のところは1が最も事例の多い変換方法でしょう。Emscripten自身のインストール方法は前回の記事をご覧いただくとして、ここではWASMを出力できるように設定を行い、Hello,Worldをコンパイルするところまでを説明します。</p>

<p>EmscripntenでWASMを出力するためには、開発版とBinaryenというツールが必要です。どちらもemsdkを利用してインストールできます。</p>

<p></p><pre class="crayon-plain-tag">$ emsdk install sdk-incoming-64bit emscripten-incoming-64bit clang-incoming-64bit
$ emsdk activate sdk-incoming-64bit emscripten-incoming-64bit clang-incoming-64bit</pre><p></p>

<p>アクティベート後は忘れずに環境変数を更新しておきます：</p>

<p></p><pre class="crayon-plain-tag">$ source ./emsdk_evn.sh</pre><p></p>

<p>では次のHello,WorldをWASMに出力します。
まず次のようなC言語で書かれたソースコードを用意します。</p>

<p></p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;

int main(int argc, char **argv){
  printf("Hello, World!\n");
}</pre><p></p>

<p>このコードをEmscriptenを使ってコンパイルします。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -o hello-world.html -s WASM=1 hello-world.c</pre><p></p>

<ul>
<li><code>-o</code>オプションでHTMLファイルを出力すること</li>
<li><code>-s WASM=1</code>を指定すること</li>
</ul>

<p>この 2 つがポイントです。特に<code>-s WASM=1</code>をつけないと、asm.jsが出力される点にご注意ください。</p>

<p>出力されたWASMファイルが動作しているかどうかは、出力されたHTMLファイルをブラウザで表示させることで確認できます。asm.jsなどはファイルを直接開いて実行を確認できましたが、WASMでは行えません。これはWASMの実行時にはクロスオリジン要求が必要で、それがfileスキームには実装されていないためです。そのため簡易なWebサーバを起動する必要があります。任意のものをお使いいただけますが、Emscriptenに同梱されている<code>emrun</code>コマンドを利用すると設定やインストールをしなくても簡易なWebサーバを起動できます。</p>

<p></p><pre class="crayon-plain-tag">$ emrun emrun --no_browser --port 8080 .</pre><p></p>

<p>上記のコマンドを実行すると、コマンドを実行したフォルダをドキュメントルートとしたWebサーバが、8080番ポートで実行されます。こちらへアクセスすることで、動作を確認できます。</p>

<h2>WASMモジュールの構造</h2>

<p>実はWASMのMVP(Minimal Viable Product/最低限の目標)はasm.jsとの互換機能の提供でした。つまりWASMはasm.jsでできることはできると思っておくと、概ね間違いはありません。例えばasm.jsファイルはソフトウェアモジュールを定義していましたが、同様にWASMファイルもソフトウェアのモジュールを定義します。</p>

<p>とはいえディテールは大きく異なります。asm.jsは（低水準とはいえ）JavaScriptとして処理できる形式でモジュールとその関数本体を定義していたのに対し、WASMは仮想的なハードウェアで動く低水準な命令の集まりとしてモジュールを定義します。WASMはその仕様で型付けされた<a href="https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%9E%E3%82%B7%E3%83%B3" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">スタックマシン</a>を定義しており、WASMファイルにはそのスタックマシンで動作するモジュールの抽象構文木（AST：Abstruct Syntax Tree）が定義されています。
抽象構文木がバイナリ形式で与えられているおかげで、ネイティブコードを出力するために必要な処理の中で重たい字句解析の全てと、構文解析の大半を省くことができます。</p>

<p>さてWASMファイルはプリアンブルと、モジュール定義の2つの部分から成っています。プリアンブルはWASMファイルであることを表すマジックナンバー（32bit）と、バージョン番号（32bit）の2つのフィールドで構成されます。モジュール定義は次の7種類のセクションを持ち得ます。依存関係はありますが、これらの全てを省略することもできます。</p>

<table>
<thead>
<tr>
  <th>セクション名</th>
  <th>説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Type</td>
  <td>関数のシグネチャ</td>
</tr>
<tr>
  <td>Import</td>
  <td>インポートするシンボルの定義</td>
</tr>
<tr>
  <td>Function</td>
  <td>関数とそのシグネチャの対応付け</td>
</tr>
<tr>
  <td>Table</td>
  <td>関数表など</td>
</tr>
<tr>
  <td>Memory</td>
  <td>メモリ領域に関する設定</td>
</tr>
<tr>
  <td>Global</td>
  <td>グローバル変数</td>
</tr>
<tr>
  <td>Export</td>
  <td>エキスポートするシンボル</td>
</tr>
<tr>
  <td>Start</td>
  <td>処理を始める関数（エントリーポイント）の定義</td>
</tr>
<tr>
  <td>Element</td>
  <td>表の要素</td>
</tr>
<tr>
  <td>Code</td>
  <td>コードセグメント。関数本体</td>
</tr>
<tr>
  <td>Data</td>
  <td>データセグメント</td>
</tr>
</tbody>
</table>

<p>asm.js同様、WASMでも関数は全て型付けされます。その型が列挙されているのがtypeセクションです。関数の型は引数の型と返り値の型を組み合わせて定義します。例えば次のような足し算を行う関数は<code>(i32, i32) -&amp;gt; i32</code>のように型付けされます。</p>

<p></p><pre class="crayon-plain-tag">int add(int a, int b){
  return a + b;
}</pre><p></p>

<p>このような関数の型のことを「シグネチャ」と呼びます。シグネチャには、それぞれidが割り振られます。このidを用いて、個々の関数を型付けしていきます。個々の関数と、その関数のシグネチャの対応づけが行われるのがfunctionセクションです。上記の<code>(i32, i32) -&amp;gt; i32</code>というシグネチャのidが0の時、次の2つの関数は0番目の関数（addのこと）のシグネチャは0、1番目の関数（subのこと）のシグネチャは1、というようにfunctionセクションへ記述されます。</p>

<p></p><pre class="crayon-plain-tag">int add(int a, int b){
  return a + b;
}
int sub(int a, int b){
  return a - b;
}</pre><p></p>

<p>それぞれの関数の本体、つまり関数定義の<code>{</code>と<code>}</code>に挟まれた部分は、codeセクションに記述されます。このセクションに記述される内容については節を分けて説明します。</p>

<p>上述したように、WASMはモジュールを定義します。つまりWASM内で定義された関数のうちいくつかは外部へと露出します。逆に外部で定義された関数を読み込んで関数を定義することもあります。露出する関数や読み込まれる関数は、それぞれexportとimportのセクションに記述されます。</p>

<p>Memoryセクションには、このモジュールで利用するヒープ領域の初期サイズが設定されます。WASMのメモリは後述しますが線形で、最大4GiBまで利用できます。このセクションで定義されるメモリサイズはあくまで初期化時に割り当てられるもので、<code>grow_memory</code>命令でより多くのメモリを確保できます。</p>

<p>これら以外のセクションもモジュールの定義に必要とされることがありますが、今回は説明を割愛します。詳しくは<a href="http://webassembly.org/docs/modules/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちらのデザイン文書</a>をご覧ください。</p>

<h2>WASMで定義される抽象構文木</h2>

<p>ここまで述べてきたWASMの特徴をまとめると、次の3点になるでしょう。</p>

<ul>
<li>バイナリフォーマット</li>
<li>モジュールの定義</li>
<li>型付けされたスタックマシンで動作する抽象構文木を表している</li>
</ul>

<p>ここからはより詳しくWASMの構造と、それが表す抽象構文木について見ていきます。</p>

<p>そのために　WASMのテキスト表現であるWASTを利用します。このWASTは現在仕様が議論中のため、将来的に記法が変わる可能性があることにご注意ください。</p>

<p>さて<code>a = 1 + 2 * 3;</code>という式は、WASTでは次のように表現されます。</p>

<p></p><pre class="crayon-plain-tag">(set_local $a
  (i32.add
     (i32.const 1)
     (i32.mul
        (i32.const 1)
        (i32.const 2)
     )
  )
)</pre><p></p>

<p>このようにとても括弧が多いのがWASTの特徴です。この記法は<a href="https://ja.wikipedia.org/wiki/S%E5%BC%8F" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">S式</a>と呼ばれるもので、<a href="https://ja.wikipedia.org/wiki/LISP" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">LISP</a>というプログラミング言語でよく用いられるもので、木やリストの形式的な記法です。<code>(</code>と<code>)</code>で囲まれたものがノードとなり、その間に挟まれた別のノードは子ノードとなります。先ほどのWASTは次の図のような木構造を表しています。</p>

<p><img src="/wp-content/uploads/2017/02/ast-wasm-300x66.png" alt="a = 1 + 2 * 3 の抽象構文木" width="300" height="66" class="aligncenter size-medium wp-image-22525" srcset="/wp-content/uploads/2017/02/ast-wasm-300x66.png 300w, /wp-content/uploads/2017/02/ast-wasm.png 640w, /wp-content/uploads/2017/02/ast-wasm-207x45.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></p>

<p><code>set_local</code>、<code>i32.add</code>、<code>i32.mul</code>、<code>i32.const</code>というのが、WASMの仕様でで定義されているスタックマシンの命令です。それぞれローカル変数への代入、加算、乗算、即値の定義を行います。四則演算や速値の定義を行う演算子は、扱うデータ型によって異なるものが用意されています。関数本体はこのように記述され、codeセクションに格納されます。</p>

<p>先ほどのWASTを使って、引数に1+2*3の結果を足す関数は次のように記述できます。詳しくは説明しませんが、なんとなく雰囲気は伝わってくるかと思います。</p>

<p></p><pre class="crayon-plain-tag">(module
  (func $addSome (param i32) (result i32)
    (local $a i32)
    (set_local $a
       (i32.add
          (i32.const 1)
          (i32.mul
            (i32.const 1)
            (i32.const 2))))
    (get_local 0)
    (get_local $a)
    (i32.add))
  (export "addSome" (func $addSome))
)</pre><p></p>

<p>なお、このWASTはスタックマシンの性質をうまく使えていません。その特徴をうまく使うと、次のようになります。</p>

<p></p><pre class="crayon-plain-tag">(module
  (type (;0;) (func (param i32) (result i32)))
  (func (;0;) (type 0) (param i32) (result i32)
    (local i32)
    i32.const 1
    i32.const 1
    i32.const 2
    i32.mul
    i32.add
    set_local 1
    get_local 0
    get_local 1
    i32.add)
  (export "addSome" (func 0)))</pre><p></p>

<p>またコンパイラで最適化処理を行うと、次のように単純化されます。1+2*3の結果をコンパイル時に計算を済ませてしまって定数とすることで、不必要な計算を省いています。</p>

<p></p><pre class="crayon-plain-tag">(module
  (type (;0;) (func (param i32) (result i32)))
  (func (;0;) (type 0) (param i32) (result i32)
    get_local 0
    i32.const 7
    i32.add)
  (export "addSome" (func 0)))</pre><p></p>

<p>WASMの構造を把握するには、<a href="https://mbebenita.github.io/WasmExplorer/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">The WASM Explorer</a>というサイトを利用されるといいでしょう。
このサイトでは、C/C++のプログラムとWASM、Firefoxによって変換されるx86のアセンブラとを比較できます。
Emscriptenで出力されたものと比べると、標準ライブラリで定義されるシンボルや関数が含まれないためコンパクトで、理解しやすいものが出力されます。</p>

<h2>WASMで扱えるデータ型</h2>

<p>WASMで扱えるデータ型は次の4つです。</p>

<table>
<thead>
<tr>
  <th>型名</th>
  <th>意味</th>
  <th>サイズ</th>
  <th>符号化方式</th>
</tr>
</thead>
<tbody>
<tr>
  <td>i32</td>
  <td>整数型</td>
  <td>32bit</td>
  <td>2の補数</td>
</tr>
<tr>
  <td>i64</td>
  <td>整数型</td>
  <td>64bit</td>
  <td>2の補数</td>
</tr>
<tr>
  <td>f32</td>
  <td>浮動小数点型</td>
  <td>32bit</td>
  <td>IEEE 754-2008</td>
</tr>
<tr>
  <td>f64</td>
  <td>浮動小数点型</td>
  <td>64bit</td>
  <td>IEEE 754-2008</td>
</tr>
</tbody>
</table>

<p>整数型と浮動小数点型とを区別して扱える点が、通常のJavaScriptとは異なります。また64bitの整数が扱える点もJavaScriptやasm.jsとも異なっています。</p>

<p>それぞれのデータ型に対して、四則演算、比較演算、即値、データのロードとストアなどの演算子が用意されています。また整数型に対してはビット演算子が、浮動小数型に対しては切り捨て、切り上げなどの演算子が用意されています。</p>

<p>また型間のデータ変換のための演算子も用意されています。32bitから64bitへの変換だけでなく、64bitから32bitへの変換も行えます。もちろん整数から小数へ、小数から整数への変換も行えます。</p>

<h3>線形メモリ</h3>

<p>WASMの命令セットはスタックマシン型として設計されていますが、メモリに対するアクセスも行えます。WASMのメモリモデルには次の特徴があります：</p>

<ul>
<li>線形</li>
<li>バイト単位でアクセス可能</li>
<li>ページ(64KiB)を単位としたメモリの増加</li>
<li>コード領域はない</li>
<li>リトルエンディアン</li>
<li>最大4GiB</li>
</ul>

<p>メモリスタックへのデータの読み込みは各データ型の持つload演算を使って行います。WASMはC/C++コードから生成されることを念頭に置いているため、load演算には、<code>i32.load_8_s</code>や<code>i32.load_16_u</code>のようなWASMにはない8bitや16bitの<code>int</code>をロードするものがあります。これらの命令はメモリ上では8bitや16bitの大きさを持つ値を、自動的に32bitへと拡張します。</p>

<p>同様にメモリへのデータ書き込みは<code>i32.store</code>のようなストア演算で行います。ストア演算も各データ型ごとに用意されており、整数型に対しては<code>i32.store8</code>や<code>i32.store16</code>のように一部分だけを保存する演算も用意されています。</p>

<p>上述したようにWASMのメモリは線形で、0から順にアドレスが付いています。ロード演算やストア演算はアドレスを使って、読み書きするメモリ上の位置を指定します。現在のところアドレスは32bitの符号なし整数で表現されます。そのため利用できるメモリの大きさは4GiBに制限されます（この制限はのちに解消される予定です）。</p>

<p>メモリは常に4GiB確保されるわけではありません。初期化時に確保される量はモジュールで定義します。プログラムの中で<code>grow_memory</code>演算を行うことで、このサイズを増やせます。また現在のメモリサイズは<code>current_memory</code>演算で取得できます。これら2つの演算はメモリをバイト単位ではなく、ページ単位で扱います。ページサイズは64KiBのため、実際のサイズはページ数に65536(16 &times; 1024)をかけた値になります。</p>

<h2>JavaScript API</h2>

<p>ここまでWASM自体について説明してきましたが、最後にJavaScriptとの連携について説明します。今の所、WASMはJavaScript APIを利用して、明示的にコンパイルし、インスタンス化する必要があります。手順としては次の通りになります：</p>

<ol>
<li>WASMファイルをダウンロードし、TypedArrayに変換</li>
<li>WASMモジュールがインポートする関数を用意する</li>
<li>1と2を利用して、WASMモジュールをインスタンス化する</li>
</ol>

<p>この手順をコード化すると次のようになります。下記の例では、上述した<code>sample.wasm</code>をインスタンス化し、そのモジュールに定義されている<code>addSome</code>を呼び出しています。</p>

<p></p><pre class="crayon-plain-tag">const importObject = {
  hello: () =&gt; console.log("Hello"),
  world: () =&gt; console.log("world")
};

fetch("sample.wasm").then(response =&gt; response.arrayBuffer())
  .then(buffer =&gt; WebAssembly.instantiate(buffer, importObject))
  .then(({module, instance}) =&gt; console.log(instance.exports.addSome(1)));</pre><p></p>

<p><code>WebAssembly.instantiate</code>が、モジュールのインスタンス化を行う関数になります。第1引数にWASMファイルがロードされたArrayBuffer演算を、第2引数にはモジュールがインポートする関数や値をまとめたオブジェクトを指定します。上の例では<code>hello</code>と<code>world</code>という2つの関数がsample.wasm内にインポートされます（実際にインポートされるかどうかは、importセクションの記述によります）。</p>

<p>インスタンス化されたされたWASMモジュールは、JavaScriptのモジュールのように扱えます。変数へ代入することもできますが、属性を追加することはできません。モジュールインスタンスは<code>exports</code>という名前の属性を持っており、その値のオブジェクトのメンバーとしてエキスポートされた関数を参照できます。</p>

<p>なお<code>WebAssembly.instantiate</code>の呼び出し時には、ダウンロードしたWASMモジュールの妥当性や、ファイルフォーマットの検証が行われます。これらに失敗した場合は、<code>WebAssembly.CompileError</code>が送出されます。これをcatchすることでコンパイルエラーを検出できます。</p>

<h2>まとめ</h2>

<p>これまで4回にわたってポータビリティや後方互換性との両立を図りつつ、ネイティブに近いスピードでの動作を実現するために行わている様々な工夫の一端を見てきました。</p>

<p>asm.jsとWebAssemblyによってネイティブに近い動作スピードは実現されつつあり、それを作成するツールもEmscriptenを筆頭に充実しつつあります。いずれフロント部分のほとんどがCやC++で実装されたWebアプリも登場するでしょう。</p>

<p>ではJavaScriptの役割は終わってしまったのでしょうか。</p>

<p>そんなことはありません。まずWebアプリの大半はasm.js/WebAssemblyで提供される計算性能を必要としていません。必要したとしても、大半のコードの価値はスピードよりもUXによって提供されるでしょう。JavaScriptの大きな特徴は、その生産性の高さです。高速に動作することよりも、高速に開発のイテレーションをまわ回して行く方が重要とされる局面は多くあるでしょう。そんな時にJavaScriptの生産性の高さが生きるでしょう。</p>

<p>ただasm.js/WASMがWebに大きな可能性を加えるものになるのは確かです。既存のWeb開発では難しかったインタラクションの多い3Dグラフィクスを扱うアプリも、UnityやUnrealEngine、Stingrayといったasm.js/WebAssemblyに対応したゲームエンジンを利用することで、効率的に開発できるようになります。工数の関係で諦めていたような表現やアプリの提案も、これらのツールを採用することで可能になる場合もあるでしょう。この連載で扱ってきた技術が、みなさまのWeb開発の選択肢に加わり、その結果Webが豊かになれば幸いです。</p>
]]></content:encoded>
		
		<series:name><![CDATA[低水準言語asm.jsとWebAssembly詳解]]></series:name>
	</item>
		<item>
		<title>Webブラウザで高速な演算を可能にする低水準言語asm.jsと、WebAssembly詳解ーC / C++をasm.jsに変換するツールEmscripten</title>
		<link>/chikoski/22494/</link>
		<pubDate>Mon, 20 Feb 2017 00:00:44 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Emscripten]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=22494</guid>
		<description><![CDATA[連載： 低水準言語asm.jsとWebAssembly詳解 (3)間が随分と空いてしまいましたが、低水準言語とasm.jsとWebAssembly詳解の第3回目です。 前回は、型システムを中心にasm.jsを解説しました...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/asmjs/" class="series-384" title="低水準言語asm.jsとWebAssembly詳解" data-wpel-link="internal">低水準言語asm.jsとWebAssembly詳解</a> (3)</div><p>間が随分と空いてしまいましたが、<a href="https://html5experts.jp/series/asmjs/" data-wpel-link="internal">低水準言語とasm.jsとWebAssembly詳解</a>の第3回目です。</p>

<p><a href="https://html5experts.jp/chikoski/18980/" data-wpel-link="internal">前回</a>は、型システムを中心にasm.jsを解説しました。asm.jsはプログラムの中に型が明示されるため、事前コンパイルをして高速に動作させられる点がasm.jsの大きな特徴でした。</p>

<p>しかし数値演算しか行えなえず、また式にすべて型アノテーションを行わなくてはならないため、通常のJavaScriptのプログラムのように手で書くのはなかなかに辛いものがあることもわかりました。</p>

<p>これはasm.jsで書かれたプログラムは、JavaScriptとしても実行可能であることが求められたためでもありました。そこでasm.jsよりも書きやすい言語で書かれたプログラムを、asm.jsに変換するツールが提案されています。</p>

<p>そのもっともよく使われている例である<a href="http://kripken.github.io/emscripten-site/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Emscripten</a>について、インストール方法や簡単な使い方、ファイルアクセス、そしてJavaScriptとの相互連携までを解説します。</p>

<h2>トランスコンパイラ Emscripten</h2>

<p>Emscriptenは<a href="https://github.com/kripken/emscripten/blob/master/LICENSE" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">オープンソース</a>のトランスコンパイラで、コンパイラフレームワークである<a href="http://llvm.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">LLVM</a>を利用して実装されています。これを利用することで、C言語やC++で書かれたプログラムをasm.jsに変換できます。</p>

<p>たとえば次のCで書かれたHello,worldもEmscriptenを使うと、asm.jsに変換され、Node.jsやWebブラウザで実行できます。</p>

<p></p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;
int main(int argc, char** argv){
  printf("Hello, world!\n");
  return 0;
}</pre><p></p>

<p>変換に利用するのがEmscriptenのフロントエンドである<code>emcc</code>コマンドです。これをgccのように使って、.cファイルをコンパイルします。次の例では、上記のHello,worldをasm.jsに変換し、Node.jsで実行しています。</p>

<p>3行目に出力されている&#8221;Hello,world!&#8221;は、Node.jsが出力しています。Cで書かれたプログラムが、Node.jsの上で動作する、というのはなかなか味わい深いものがありますね。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -o hello.js hello.c
$ node hello.js
Hello, world!</pre><p></p>

<p>Emscriptenは、自分の書いたプログラムだけでなく、libcやlibc++といった標準ライブラリも一緒に変換します。</p>

<p>上記の例ではCの標準関数も一緒に変換が行われているため、<code>printf</code>が正しく実行されています。</p>

<p>またOpenGLの関数呼び出しはWebGLへ変換されます。<a href="https://www.libsdl.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">SDL</a>の関数も利用できるため、<a href="https://github.com/kripken/emscripten/blob/master/tests/hello_world_sdl.cpp" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">次のようなSDLを用いたプログラム</a>も変換できます。</p>

<p>これらはCanvas要素をディスプレイ代わりに利用するため、変換時にJavaScriptだけでなくHTMLも合わせて出力させることで<a href="https://chikoski.github.io/wasm-demo/hello-sdl/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">実行</a>できます。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -o hello-world-sdl.html hello-world-sdl.cpp</pre><p></p>

<h2>Emscriptenのインストール</h2>

<p>Emscriptenはemsdkというツールを利用してインストールします。このツールは単なるインストーラではなく、<a href="https://github.com/creationix/nvm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nvm</a>や<a href="https://www.rustup.rs/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">rustup</a>、<a href="https://rvm.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">rvm</a>のようなツールで、使用するEmscriptenのバージョン指定や更新を行えます。</p>

<p>emsdkとEmscriptenのインストールは<a href="https://github.com/juj/emsdk" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">配布元のサイト</a>で確認いただけますが、概要を述べると次のようになります。</p>

<ol>
<li>依存するツールのインストール：GCC/Git/Cmake/Python 2.7.x
2.emsdkのクローンと更新</li>
<li>最新版のEmscriptenのインストール</li>
<li>インストールしたEmscriptenの有効化</li>
</ol>

<p>emsdkはGitHubで配布されています。また内部の処理にGitを利用します。またEmscriptenのインストールや更新時にclangのコンパイルを行います。cmakeやgccはそのコンパイルに利用されます。</p>

<p>環境によってインストール方法は異なります。それぞれの環境にあった方法でインストールしてください。<a href="http://brew.sh/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Homebrew</a>を利用できるようになっているmacOSの場合、GCC/Git/Pythonはすでにインストールされています。CMakeは次のように<code>brew</code>コマンドを使ってインストールできます。</p>

<p></p><pre class="crayon-plain-tag">$ brew install cmake # cmake のインストール</pre><p></p>

<p>依存するツールをインストールしたらemsdkをクローンします。</p>

<p></p><pre class="crayon-plain-tag">$ git clone https://github.com/juj/emsdk.git
$ cd emsdk</pre><p></p>

<p>emsdkフォルダ内にある、emsdkというファイルを使って、Emscriptenの管理を行います。</p>

<p>まず<code>update</code>コマンドを実行して、emsdkそのものと、インストール可能なEmscriptenのバージョンリストを最新のものへと更新します。次に<code>install</code>コマンドを実行して、最新の安定板をインストールします。</p>

<p></p><pre class="crayon-plain-tag">$ ./emsdk update
$ ./emsdk install latest</pre><p></p>

<p>インストールしただけでは、Emscriptenを利用できるようにはなりません。<code>activate</code>コマンドで利用するEmscriptenのバージョンを指定し、環境変数を設定することで、インストールした最新バージョンのEmscriptenが利用できるようになります。</p>

<p></p><pre class="crayon-plain-tag">$ ./emsdk activate latest
$ source ./emsdk_env.sh</pre><p></p>

<h2>Hello, world!</h2>

<p>asm.jsへのコンパイルはemccコマンドを利用して行います。まずは正しくインストールできたかどうかを確認するために、バージョン番号を表示させてみましょう。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -v</pre><p></p>

<p>バージョン番号が表示されれば正しくインストールできています。次はHello,worldでしょう。次のようなプログラムを作成し、hello.cという名前で保存します。</p>

<p></p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;

int main(int argc, char** argv){
  printf("Hello, world!\n");
  return 0;
}</pre><p></p>

<p>プログラムを作成したら、つぎのコマンドを実行します。</p>

<p></p><pre class="crayon-plain-tag">$ emcc hello.c</pre><p></p>

<p>a.out.jsというファイルが作成されます。これが上記のプログラムがEmscriptenによって変換された結果です。nodeで実行させてみましょう。</p>

<p>ターミナルに&#8221;Hello,world!&#8221;と出力されるはずです。</p>

<p></p><pre class="crayon-plain-tag">$ node a.out.js</pre><p></p>

<h2>emcc コマンド</h2>

<p>emccコマンドには、<a href="http://kripken.github.io/emscripten-site/docs/tools_reference/emcc.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">いくつものオプション</a>があります。それらのうち、よく使うものをまとめると次の表になります。</p>

<table>
<thead>
<tr>
  <th>オプション</th>
  <th>効果</th>
</tr>
</thead>
<tbody>
<tr>
  <td><code>-o &amp;lt;file&amp;gt;</code></td>
  <td>出力するファイル名を指定する</td>
</tr>
<tr>
  <td><code>-O0</code></td>
  <td>最適化を全く行わない</td>
</tr>
<tr>
  <td><code>-O1</code></td>
  <td>LLVMの<code>-O0</code>最適化や、アサーションの削除といった最適化が行われる</td>
</tr>
<tr>
  <td><code>-O2</code></td>
  <td><code>-O1</code>に加えて、出力するJavaScriptの最適化も行う</td>
</tr>
<tr>
  <td><code>-O3</code></td>
  <td><code>-O2</code>に加えて、さらなる最適化をJavaScriptに対して行う。遅い</td>
</tr>
<tr>
  <td><code>-g</code></td>
  <td>デバッグ情報を保持する</td>
</tr>
<tr>
  <td><code>--preload-file &amp;lt;path&amp;gt;</code></td>
  <td>プログラム中で読み書きするファイルの場所を指定する</td>
</tr>
<tr>
  <td><code>--embed-file &amp;lt;path&amp;gt;</code></td>
  <td>プログラムに埋め込むファイルの場所を指定する</td>
</tr>
</tbody>
</table>

<p><code>-o</code>オプションを使うと出力するファイル名を指定だけでなく、ターゲットの変更もできます。
例えば.htmlで終わるファイル名を指定することで、HTMLを出力できます。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -o hello.html hello.c
$ ls
hello.c		hello.html	hello.js</pre><p></p>

<p>出力されたHTMLファイルをブラウザで表示させると、次のように&#8221;Hello,world!&#8221;と出力されていることが確認できます。</p>

<p><img src="/wp-content/uploads/2017/02/helloworld-html-300x170.png" alt="ブラウザで実行されるHello, World" width="300" height="170" class="aligncenter size-medium wp-image-22505" srcset="/wp-content/uploads/2017/02/helloworld-html-300x170.png 300w, /wp-content/uploads/2017/02/helloworld-html.png 640w, /wp-content/uploads/2017/02/helloworld-html-207x117.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></p>

<h2>ファイルも扱えます</h2>

<p>Node.js同様、C/C++のプログラムはファイルに対する操作が行えます。C/C++の標準的なライブラリで提供されている機能を利用してreadme.txtというファイルを読み込むプログラム実装すると、次のようになります。</p>

<p></p><pre class="crayon-plain-tag">#include 

int main(int argc, char** argv){
  FILE *file = fopen("readme.txt", "r");
  while(!feof(file)){
    char c = fgetc(file);
    if(c == EOF){
      break;
    }
    putchar(c);
  }
  fclose(file);
  return 0;
}</pre><p></p>

<p>このコードの中のfopen,feof,fgetc,fcloseがファイルアクセスに関する関数になります。これらの関数の呼び出しは同期的に行われます。このコードもEmscriptenで変換できますし、正しく動作します。</p>

<p>そもそもブラウザ内で動作するJSはファイルにアクセスできません。</p>

<p>また、このコードはファイルアクセスが同期的に処理されているため、そのまま変換を行うとアクセスが終わるまで、ブラウザの処理が止まってしまいます。下図のような仮想的なファイルシステムを提供することで、Emscriptenはこれらの問題を解決しています。</p>

<div id="attachment_22529" style="width: 310px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2017/02/emscripten-filesystem-architecture-300x178.png" alt="Emscripten で提供されるファイルシステム" width="300" height="178" class="aligncenter size-medium wp-image-22503" srcset="/wp-content/uploads/2017/02/emscripten-filesystem-architecture-300x178.png 300w, /wp-content/uploads/2017/02/emscripten-filesystem-architecture-207x123.png 207w, /wp-content/uploads/2017/02/emscripten-filesystem-architecture.png 619w" sizes="(max-width: 300px) 100vw, 300px" /><p class="wp-caption-text"><a href="https://kripken.github.io/emscripten-site/docs/porting/files/file_systems_overview.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">File System Overview</a> より引用</p></div>

<p>まずSynchronous File System APIによって、同期的な関数呼び出しを非同期的なものに変換しています。</p>

<p>このAPIはファイルシステムの実装も隠蔽しています。通常はメモリ上に構築されるファイルシステムを利用しますが、コンパイル時のオプションによってNode.jsのファイルシステムや、IndexedDBを利用したものを利用できます。この切り替えを行ったとしても、コードを変更する必要はありません。</p>

<p>Emscriptenの仮想ファイルシステムはPOSIXのファイルシステムと同様に、デバイスファイルの作成や、ファイルシステムのマウントなどもサポートしています。</p>

<p>これらの機能は<a href="http://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.htm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">FileSystem API</a> 経由で利用できます。標準入出力も自作のオブジェクトに置き換えられますので、なかなかに工夫しがいのあるかと思います。</p>

<h2>アセットを追加するには</h2>

<p>上記の例で利用したreadme.txtのようなアセットを利用するためには、Emscriptenによって提供される仮想ファイルシステムにアセットのファイルを追加する必要があります。</p>

<p>追加方法には、次の2つがあります。</p>

<p>ファイルサイズの大きいものや更新が頻繁なものは後者で、そうでないものは前者の方法を利用するとよいでしょう。</p>

<ul>
<li>利用するファイルをJSに埋め込む方法</li>
<li>利用されるファイルを1つにまとめ、それをXHRで読み込む方法</li>
</ul>

<p>前者は<code>--embed-file</code>オプションを、後者は<code>--preload-file</code>オプションをつけて<code>emcc</code>を実行することで、利用できます。</p>

<p>例えば先ほど紹介したプログラムはreadme.txtというファイルを読み込み、その内容を標準出力へと出力します。これを後者の方法で変換するには、次のように<code>emcc</code>コマンドを実行します。</p>

<p></p><pre class="crayon-plain-tag">$ emcc -o read-file.html --preload-file readme.txt read-file.c</pre><p></p>

<p>実行すると、HTMLファイルやJSファイル以外に<code>.data</code>ファイルが作成されます。</p>

<p>これはアセットを一つにまとめたものです。このファイルを非同期に読み込み、メモリ上に配置することで、Emscriptenはアセットのロードを実現させています。</p>

<div id="attachment_22529" style="width: 310px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2017/02/emscripten-reading-asset-300x170.png" alt="ファイルを読むコードの実行例" width="300" height="170" class="aligncenter size-medium wp-image-22504" srcset="/wp-content/uploads/2017/02/emscripten-reading-asset-300x170.png 300w, /wp-content/uploads/2017/02/emscripten-reading-asset.png 640w, /wp-content/uploads/2017/02/emscripten-reading-asset-207x117.png 207w" sizes="(max-width: 300px) 100vw, 300px" /><p class="wp-caption-text">文章は<a href="https://ja.wikipedia.org/wiki/Emscripten" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">WikiPedia のEmscriptenの項目</a> より引用</p></div>

<h2>インライン JavaScript</h2>

<p>C/C++には、インラインアセンブラという機能があります。これはアセンブラで書かれたコードをソースコードの中に埋め込んでしまえる、というもので、高速化やシステムコールの実現などのために利用されます。</p>

<p>同様にEmscriptenでは、ソースコードの中にJavaScriptを埋め込めます。JavaScriptを埋め込むことで、C/C++のコードからブラウザの機能を利用できるようになります。</p>

<p>埋め込むためには<code>EM_ASM()</code>と呼ばれるマクロを使います。</p>

<p><code>alert</code>関数を呼び出すコードは、次のように書けます。</p>

<p></p><pre class="crayon-plain-tag">#include 

int main(){
  EM_ASM(
    alert("Hello, world!");
  );
  return 0;
}</pre><p></p>

<p>これを<code>emcc</code>でコンパイルして、実行した結果は次のようになります。</p>

<p><img src="/wp-content/uploads/2017/02/em-asm-300x171.png" alt="Cに埋め込まれたJavaScriptの実行例" width="300" height="171" class="aligncenter size-medium wp-image-22509" srcset="/wp-content/uploads/2017/02/em-asm-300x171.png 300w, /wp-content/uploads/2017/02/em-asm.png 640w, /wp-content/uploads/2017/02/em-asm-207x118.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></p>

<p><code>EM_ASM_</code>を利用すれば、パラメーターを与えることもできます。<code>EM_ASM</code>との違いは、埋め込むJSのコードがブロックになっている点と、マクロの名前です。パラメータを与えるマクロは、末尾に<code>_</code>がついています。間違えがちなので注意が必要です。</p>

<p></p><pre class="crayon-plain-tag">#include 

int main(){
  EM_ASM_({
    alert(`Hello, world: ${$0}`);
  }, 100);
  return 0;
}</pre><p></p>

<p>与えられたパラメータは、<code>$0</code>,<code>$1</code>のように参照できます。上記の例では、与えられたパラメータをテンプレート文字列内で利用しています。</p>

<p>これらのマクロは<code>emscripten.h</code>に定義されています。詳しくは<a href="kripken.github.io/emscripten-site/docs/api_reference/emscripten.h.html" data-wpel-link="internal">ドキュメント</a>を参照してください。</p>

<h2>外部関数としてJavaScript関数を呼び出す</h2>

<p>マクロとしてJavaScriptを埋め込む以外に、C/C++からJavaScriptの関数を呼び出せます。それは外部関数として関数を宣言しておき、Emscriptenの<code>--js-library</code>オプションで実装を与える方法です。</p>

<p>次のコードでは、<code>zero</code>という関数を呼び出しています。この関数は外部の関数として宣言されています。、コンパイラは名前、引数の数と型、返り値の型以外わかっていません。</p>

<p></p><pre class="crayon-plain-tag">extern int zero();

int one(){
  return zero() + 1;
}</pre><p></p>

<p>通常のC/C++では、C/C++のコード（時にはコンパイル済みのバイナリ）として、この関数の実装は与えられますが、Emscriptenでは、これらに加えてJavaScriptでその実装を与えることもできます。</p>

<p>次のようにJavaScriptで<code>zero</code>を実装し、<code>LibraryManager</code>オブジェクトの<code>library</code>属性にマージしてやることで、C/C++のコードから呼び出せるようになります。</p>

<p></p><pre class="crayon-plain-tag">function zero(){
  return 0;
}

mergeInto(LibraryManager.library, {
  zero: zero
});</pre><p></p>

<h2>JavaScriptから変換されたコード利用するには</h2>

<p>基本的な機能はC/C++で実装済みで、それを操作するUIをWebで提供したい。そんな場合は、Emscriptenで変換されたC/C++のコードを、JSから呼び出すかたちで実装するとよいでしょう。</p>

<p>まず基本であるCで定義された関数をJSから呼び出してみましょう。次のような足し算を行う関数が、add.cというファイルに定義されていたとしましょう。</p>

<p></p><pre class="crayon-plain-tag">int add(int a, int b){
  return a + b;
}</pre><p></p>

<p>これを<code>emcc</code>コマンドでJSに変換します。</p>

<p></p><pre class="crayon-plain-tag">% emcc -o add.js -s "EXPORTED_FUNCTIONS=['_add']" add.c</pre><p></p>

<p><code>-s</code>オプションを使うと、コマンドラインオプションでは指定できない内部的なオプションを指定できます。</p>

<p>これを利用してJSへエキスポートする関数のリストである<code>EXPORTED_FUNCTIONS</code>を設定しています。このリストに載せる関数は、その名前の先頭に<code>_</code>をつけなければならないことに注意してください。</p>

<p>またC++の場合は、関数がマングリングされるの防ぐために、次のようにCのプログラムとして記述する必要があります。</p>

<p></p><pre class="crayon-plain-tag">extern "C"{
  int add(int a, int b){
    return a + b;
  }
}</pre><p></p>

<p>生成されたadd.jsをロードした後、次のようにJS側でasm.jsの関数をラップしたJavaScriptの関数を作成します。</p>

<p></p><pre class="crayon-plain-tag">const add = Module.cwrap("add", "number", ["number"]);</pre><p></p>

<p><code>Module</code>オブジェクトは、Emscriptenによって自動的に定義されるオブジェクトで、生成されたコードが実行されるときに、さまざまな形で利用されます。そのcwrapメソッドを使って、asm.jsの関数をJavaScriptから利用できるようにします。そのメソッドの引数はそれぞれ、ラップする関数の名前、返り値の型、引数の型を表します。</p>

<p>一度ラップされてしまえば、JavaScriptの関数と区別することなく利用できます。</p>

<p></p><pre class="crayon-plain-tag">const sum = add(1, 2); // 3
console.log(sum);</pre><p></p>

<p>C++で書かれたコードに対しては、上記の方法に加えて、C++で定義されたクラスをJavaScriptから利用できるようになります。これの詳細については述べませんが、手順を概観すると次のようになります：</p>

<ul>
<li>C++で定義されたクラスのためのWebIDLを作成する</li>
<li>作成したWebIDLを<code>tools/webidl_binder.py</code>で処理して、グルーコードを作成する</li>
<li>グルーコードとともに、cppファイルを<code>emcc</code>コマンドでコンパイルする</li>
</ul>

<p>上記の手順で処理することによって、C++で定義されたクラスを作成するコンストラクタが、<code>Module</code>オブジェクトの属性として参照できるようになります。</p>

<p>詳しくは<a href="http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.html#webidl-binder" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちらのドキュメント</a>を参照してください。</p>

<h2>まとめ</h2>

<p>手で書くのが大変なasm.jsも、CやC++で書いたコードをEmscriptenで変換することで簡単に生成できます。このとき標準ライブラリの変換も合わせて行われます。</p>

<p>またファイルシステムもEmscriptenによってエミュレートされるため、asm.jsへの変換を行う際にソースコードを変更する必要はほとんどありません。C/C++のコードをほとんど変えなくても、asm.jsへと変換できます。</p>

<p>またJavaScriptと変換されたコードの相互呼び出しも可能な上に、標準入出力もJSでエミューレートできます。そのおかげで、Emscriptenで作られたasm.jsコードと、JavaScriptで作られたコードとを柔軟に組み合わせてサイトやアプリを作ることができます。</p>

<p>これでめでたしめでたし、とならないのが技術の世界のつらいところです。Emscriptenによって作られたコードにも弱点があります。それはロードにかかる時間です。単なるHello Worldであっても、変換されたコードは300Kバイト程度になります。これは合わせて変換された標準ライブラリが、コードに含まれているためです。</p>

<p>コードのサイズは、Hello Worldなので300K程度で済んでいるともいえます。これがゲームともなれば、そのサイズはさらに増大します。コードサイズの大きさは、ダウンロードにかかる時間が大きいことも意味しますし、ダウンロード後、起動までの時間が長くなることも意味します。</p>

<table>
<thead>
<tr>
  <th>プログラム</th>
  <th>コードのサイズ（asm.js）</th>
  <th>コードのサイズ（WebAssembly）</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Hello World</td>
  <td>301KiB</td>
  <td>204KiB</td>
</tr>
<tr>
  <td>AngryBots</td>
  <td>19MiB</td>
  <td>6MiB</td>
</tr>
<tr>
  <td>StandardAssets</td>
  <td>25.7MiB</td>
  <td>13.4MiB</td>
</tr>
<tr>
  <td>UnityChan-CRS</td>
  <td>21.3MiB</td>
  <td>11.4MiB</td>
</tr>
</tbody>
</table>

<p>この問題を解決するために、新しいファイルフォーマットの議論が始まりました。それがWebAssemblyです。</p>

<p>上の表をご覧いただければ、WebAssemblyを利用することでファイルサイズがぐっと小さくなっていることがわかるかと思います。最終回となる次回はWebAssemblyの役割と、その特徴について解説します。</p>
]]></content:encoded>
		
		<series:name><![CDATA[低水準言語asm.jsとWebAssembly詳解]]></series:name>
	</item>
		<item>
		<title>Webブラウザで高速な演算を可能にする低水準言語asm.jsと、WebAssembly詳解ーasm.jsの仕組みとコーディング例</title>
		<link>/chikoski/18980/</link>
		<pubDate>Mon, 25 Jul 2016 00:06:51 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=18980</guid>
		<description><![CDATA[連載： 低水準言語asm.jsとWebAssembly詳解 (2)連載の第１回目は asm.jsの紹介と、asm.jsが導入された背景を概観しました。 Just in Timeコンパイルによって高速にJavaScript...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/asmjs/" class="series-384" title="低水準言語asm.jsとWebAssembly詳解" data-wpel-link="internal">低水準言語asm.jsとWebAssembly詳解</a> (2)</div><p>連載の<a href="https://html5experts.jp/chikoski/18964/" target="_blank" data-wpel-link="internal">第１回目</a>は asm.jsの紹介と、asm.jsが導入された背景を概観しました。</p>

<p>Just in Timeコンパイルによって高速にJavaScriptを実行できるようになりましたが、立ち上がりが遅い、やり直しが発生する、コンパイルによって一時的に負荷が向上する、といった問題が残されています。</p>

<p>これを解決するためにプログラムの実行を行うより前にネイティブコードへとコンパイルするAhead of Timeコンパイルを導入したいのですが、JavaScriptは柔軟すぎて効率の良いネイティブコードを出力することが難しい、という問題がありました。</p>

<p>asm.jsはこの問題に一定の解をあたえるものとなります。今回はそのasm.jsがどのようなものなのか、JavaScriptの関数を asm.js化しながら解説していきます。</p>

<h2>asm.jsがコンパイルされるまで</h2>

<p>前述したとおりasm.jsで記述されたプログラムは、実行以前にコンパイルされます。コンパイルは下図のような過程で行われます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/05/aot.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/05/aot.png" alt="asm.jsがコンパイルされるまで。意味解析とリンク時のチェックが行われ、失敗すると通常のJSとして実行される。" class="aligncenter size-medium wp-image-18967" srcset="/wp-content/uploads/2016/05/aot.png 640w, /wp-content/uploads/2016/05/aot-300x75.png 300w, /wp-content/uploads/2016/05/aot-207x52.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>ソースコードが字句解析、構文解析されてAST（Abstract Syntax Tree：抽象構文木）になるところまでは一緒ですが、その後意味解析が行われます。この意味解析でそれぞれの式や変数、関数の型がチェックされます。</p>

<p>意味解析が終了後、プログラムはコンパイルされネイティブコードが出力されます。このネイティブコードはメモリ上に展開されたあと、プログラム中で利用しているJavaScriptの関数やasm.jsに用意されている標準ライブラリとのリンクが行われます。</p>

<p>意味解析とリンク、この2つに失敗する場合もあります。プログラム中に型エラーが発見された場合は前者の失敗します。
後者はメソッドの呼び出しや、JSにエキスポートできない種類のデータを引数に指定した関数呼び出しを行った場合に失敗します。</p>

<p>このような場合、プログラムはasm.jsとして処理されるのではなく、通常のJSとして処理されます。asm.jsがJSのサブセットであることによって、このようなフォールバックも可能になっています。</p>

<h2>asm.jsモジュール</h2>

<p>asm.jsで書かれたプログラムとして事前コンパイルされる際の単位は、モジュールです。ファイル単位でコンパイルが行われるわけではないので、1つのJSファイルのうち高速化が必要な部分をasm.jsで書き、それ以外の部分は通常のJSとして書くといったことが可能です。</p>

<p>asm.jsのモジュールは、次のようにCやC++のソースコードと似た構造となっています。</p>

<p></p><pre class="crayon-plain-tag">function ModuleName(stdlib, ffi, heap){
"use asm";
 // (1) 外部からインポートするシンボルの宣言
 // (2) 関数宣言
 // (3) 関数表の宣言
 // (4) モジュールのエキスポート
}</pre><p></p>

<p>1の部分では利用する標準ライブラリや、JSの関数、定数などのシンボルを列挙します。ちょうどCのextern宣言と同じような役割です。</p>

<p>2の部分で、それぞれの処理を関数として定義します。asm.jsではオブジェクトやクラスの定義が許されていません。そのため処理はクラスやオブジェクトとしてではなく、あくまで関数として定義します。</p>

<p>3の部分では同じ型の関数をまとめた表を定義できます。ちょうどCでの関数ポインタの機能を代替するものです。関数を直接呼び出すのではなく、この表を参照する形で呼び出すことで、呼び出す関数の振る舞いを変えられるので、多態性を持った関数を定義したい場合に有用です。</p>

<p>とはいえ、いまいちイメージがつかめないかと思います。そこで足し算を行うモジュールをasm.js化しながら、構成を見てゆきましょう。変更するのは以下のようなモジュールです。</p>

<p></p><pre class="crayon-plain-tag">function AddFunctions(){
  function add1(value){
    var result;
    result = value + 1;
    return result;
  }
  return {
    add1: add1
  }
}</pre><p></p>

<p>このモジュールは次のように利用できます。</p>

<p></p><pre class="crayon-plain-tag">const module = AddFunctions();
const one = module.add1(0);    // 1
const two  = module.add1(one); // 2</pre><p></p>

<h3>asm.jsディレクティブ</h3>

<p>asm.js化の第一歩は、ディレクティブの追加です。&#8221;use strict&#8221; ディレクティブをつけると、その関数はstrict modeで解釈されるのと同様に、&#8221;use asm&#8221;ディレクティブをつけることで、処理系はその関数をasm.jsのモジュール定義として処理します。</p>

<p></p><pre class="crayon-plain-tag">function AddFunctions(){
  "use asm";
  function add1(value){
    var result;
    result = value + 1;
    return result;
  }
  return {
    add1: add1,
  }
}</pre><p></p>

<h2>　型アノテーション</h2>

<p>次にAOTを行うための型アノテーションを行います。型アノテーションは、TypeScriptなどのように型を直接記述する方法が一般的かと思いますが、JavaScriptとしても解釈できなくてはいけないasm.jsでは異なります。同値となるような式を追加することで、型情報を明示します。</p>

<p>明示的に型アノテーションを行う対象は次の3つです。</p>

<ul>
<li>関数の引数</li>
<li>変数</li>
<li>関数の返り値</li>
</ul>

<p>これらの情報を元に、関数の型や式の型が決定されます。</p>

<h4>引数に対する型アノテーション</h4>

<p>引数に対する型アノテーションは、関数本体の先頭で行います。次の例では、add1の引数valueの型はintであることを示す型アノテーションが加わっています。value = value | 0; が型アノテーションを行っている部分です。</p>

<p></p><pre class="crayon-plain-tag">function AddFunctions(){
  "use asm";
  function add1(value){
    value = value | 0;
    var result;
    result = value + 1;
    return result;
  }
  return {
    add1: add1
  }
}</pre><p></p>

<p>引数で利用できる型はint, doubleの2つです。それぞれの型はは次の表のようにアノテーションします。</p>

<table>
<thead>
<tr>
  <th>型</th>
  <th>型アノテーション</th>
</tr>
</thead>
<tbody>
<tr>
  <td>int</td>
  <td>value = value | 0</td>
</tr>
<tr>
  <td>doube</td>
  <td>value = +value</td>
</tr>
<tr>
  <td>float</td>
  <td>value = f(value)</td>
</tr>
</tbody>
</table>

<p>尚、外部で定義された関数呼び出しを行った場合は、floatとして解釈されます。</p>

<h3>変数宣言</h3>

<p>asm.jsでは、関数内で利用する変数に対しても型アノテーションを行います。これは宣言時に初期値として代入するを適切に選ぶ形で行います。整数値を代入すればintに、実数値の場合はdoubleとなります。</p>

<p>尚、1.0のような小数点以下の数字が0のものは実数値として扱われます。変数宣言に型アノテーションをつけると、先ほどまでのモジュールは以下のようになります。</p>

<p></p><pre class="crayon-plain-tag">function AddFunctions(){
  "use asm";
  function add1(value){
    value = value | 0;
    var result = 0; // intとして宣言
    result = value + 1;
    return result;
  }
  return {
    add1: add1
  }
}</pre><p></p>

<h3>返り値に対する型アノテーション</h3>

<p>返り値に対して型アノテーションを行います。この情報と引数の型情報とを組み合わせて、関数の型が決定されます。</p>

<p>返り値で利用できるのはdouble, signed, float, そしてvoidの4つの型です。それぞれのアノテーション方法は以下の表の通りです。また即値を書く場合は、アノテーションは必要ありません。</p>

<table>
<thead>
<tr>
  <th>型</th>
  <th>アノテーション例</th>
  <th>メモ</th>
</tr>
</thead>
<tbody>
<tr>
  <td>double</td>
  <td>return +result;</td>
  <td></td>
</tr>
<tr>
  <td>signed</td>
  <td>return result</td>
  <td>0|</td>
</tr>
<tr>
  <td>float</td>
  <td>return f(result)</td>
  <td>fは関数</td>
</tr>
<tr>
  <td>void</td>
  <td>return;</td>
  <td></td>
</tr>
</tbody>
</table>

<h3>asm.jsの型システム</h3>

<p>これまでintやdoubleといった型を利用してきましたが、asm.jsで利用できる型を列挙し、それぞれの継承関係を示すと次の図となります。
矢印の元にある型は先の型を継承しています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/05/subtypes.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/05/subtypes.png" alt="asm.js の型システム" class="aligncenter size-medium wp-image-18970" srcset="/wp-content/uploads/2016/05/subtypes.png 640w, /wp-content/uploads/2016/05/subtypes-300x134.png 300w, /wp-content/uploads/2016/05/subtypes-207x93.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a>
<a href="http://asmjs.org/spec/latest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://asmjs.org/spec/latest</a> より引用</p>

<p>継承するということは、何かの制約が厳しくなっていくということです。asm.jsの型システムではnullを許容するか、実行時に割り当てられるレジスタがdoubleかintか、といった点での制約が厳しくなっていきます。</p>

<p>また、JavaScriptで定義されている関数に渡せる型も決まっています。背景色が薄い灰色になっているfixnum / signed / extern / double型のデータのみが許可されています。</p>

<h3>型のキャスト</h3>

<p>先ほどから変更しているプログラムは、意味解析に失敗します。それは次の部分に原因があります。</p>

<p></p><pre class="crayon-plain-tag">result = value + 1;</pre><p></p>

<p>これはint+fixnumの計算を行い、その結果をint型の変数に代入しようとしています。型エラーの入り込む余地はなさそうに思えます。しかし、この加算の評価値の型はinterishとなっています。そのため、int型へinterish型の値を代入することになり、型エラーが起きるというわけです。</p>

<p>そこでキャストを行い、演算結果の型を明示します。この変更をおこないasm.jsの意味解析に成功するコードは次のようになります。</p>

<p></p><pre class="crayon-plain-tag">function AddFunctions(){
  "use asm";
  function add1(value){
    value = value | 0;
    var result = 0; // int として宣言
    result = (value + 1) | 0; // int へキャスト
    return result;
  }
  return {
    add1: add1
  }
}</pre><p></p>

<h2>JavaScriptとの組み込み</h2>

<p>以上で、AddFunctionsモジュールをasm.js化することができました。これをJavaScriptのプログラムに組み込みんでいきます。</p>

<p>ここでは 上記で作成したAddFunctionsモジュールをJavaScript側から利用する方法と、AddFunctionsモジュール内で JavaScriptの関数を利用する方法について説明します。</p>

<h3>JavaScriptからの利用</h3>

<p>asm.jsのモジュールとJavaScriptのモジュールは、JavaScriptからみると区別できません。下記のようにJSのモジュールを呼ぶように利用できます。</p>

<p></p><pre class="crayon-plain-tag">const module = AddFunctions();
var one = module.add1(0);
var two = module.add1(one);

function add2(n){
  return module.add1(module.add1(n));
}</pre><p></p>

<h3>JavaScriptの関数をasm.jsから呼ぶには</h3>

<p>まず、asm.jsの内部からJavaScriptで定義された関数を呼ぶことはできます。また、Mathオブジェクトの持っているいくつかのメソッドは、<a href="http://asmjs.org/spec/latest/#standard-library" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">標準ライブラリ中の関数</a>として提供されています。</p>

<p>これら関数への参照はモジュールを定義する関数の引数として与えます。例えば、AsmModuleにasm.jsモジュールが定義されている場合、次のように呼び出すことでJavaScriptの関数をasm.js内から呼び出せます。</p>

<p></p><pre class="crayon-plain-tag">const ffi = {
  put: n =&gt; console.log(n)
};

const module = AsmModule(window, ffi);</pre><p></p>

<p>asm.jsで定義される関数はオブジェクトの解決ができません。そのため利用する関数はあらかじめ外部からインポートするシンボルとして宣言しておきます。</p>

<p>次の例では、標準ライブラリ中のMath.expとMath.log、そして自作関数であるputを外部からインポートするシンボルとして宣言しています。</p>

<p></p><pre class="crayon-plain-tag">function AsmModule(stdlib, ffi, heap){
  "use asm";
  var exp = std.lib.Math.exp;
  var log = std.lib.Math.log;

  var put = ffi.put;</pre><p></p>

<p>これらの関数は、関数定義内でasm.js内部で定義された関数と同様に呼び出せます。ただ1点注意しなくてはならないのは、引数に渡すデータの型です。標準ライブラリ以外の外部関数に渡せるのはfixnum、signed、extern、doubleのいずれかです。
それ以外の値を渡すとリンクエラーとなり、通常のJSとして実行されます。演算の結果を適切にアノテーションすることで、リンクエラーを避けられます。</p>

<p></p><pre class="crayon-plain-tag">var value = 1;
put(value + 1); // リンクエラー
put((value + 1) | 0); // OK</pre><p></p>

<h2>ヒープの利用</h2>

<p>asm.jsで定義される関数は、数値演算しかできません。また、オブジェクトの解決もできません。つまり、次のような関数は定義できないことになります。</p>

<p></p><pre class="crayon-plain-tag">function caesar(string, key){
  var result = "";
  for(let i = 0; i &lt; string.length; i++){
    result += String.fromCharCode(a.charCodeAt(0)+key);
  }
  return result;
}</pre><p></p>

<p>ところでC言語では文字列を数値の配列として扱います。この考えを応用すれば、asm.jsでも文字列を数値演算の範囲で扱えるようになります。</p>

<p>上記の関数をasm.jsに書き直すと以下のようになります。</p>

<p></p><pre class="crayon-plain-tag">function Caesar(stdlib, ffi, heap){
  "use asm";
  var HEAP = new stdlib.Int8Array(heap);

  function encrypt(key){
    key = key | 0;
    var i = 0;
    for(;(HEAP[i &lt;&lt; 0 &gt;&gt; 0] | 0) != 0; i = i + 1 | 0){
      buffer[i &lt;&lt; 0 &gt;&gt; 0] = ((buffer[i &lt;&lt; 0 &gt;&gt; 0] | 0) + key) | 0;
    }
    return;
  }</pre><p></p>

<p>文字列はHEAPというArrayBufferに格納されています。このArrayBufferはモジュールの定義時に引数として与えられます。
ArrayBufferのビューは標準ライブラリとして提供されているため、上記のようにモジュール内のHEAPを大域変数として宣言する際にビューもあわせて定義します。</p>

<p>HEAPの添字は、ビューの各要素の大きさに合わせてシフトする必要があります。シフトするビット数は、2を底として要素のバイトサイズのlogをとると求まります。</p>

<p>上記の例で利用しているInt8Arrayの場合、各要素の大きさは1バイトのため、0ビットシフトしています。ビューとシフトするビット数の対応は次の表を参照してください。</p>

<table>
<thead>
<tr>
  <th>ビュー</th>
  <th>要素のサイズ（バイト）</th>
  <th>シフトするビット数</th>
  <th>ロード時の型</th>
  <th>保存時の型</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Uint8Array</td>
  <td>1</td>
  <td>0</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Int8Array</td>
  <td>1</td>
  <td>0</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Uint16Array</td>
  <td>2</td>
  <td>1</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Int16Array</td>
  <td>2</td>
  <td>1</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Uint32Array</td>
  <td>4</td>
  <td>2</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Int32Array</td>
  <td>4</td>
  <td>2</td>
  <td>intish</td>
  <td>intish</td>
</tr>
<tr>
  <td>Float32Array</td>
  <td>4</td>
  <td>2</td>
  <td>float?</td>
  <td>floatish, double?</td>
</tr>
<tr>
  <td>Float64Array</td>
  <td>8</td>
  <td>3</td>
  <td>double?</td>
  <td>float?, double?</td>
</tr>
</tbody>
</table>

<p>ArrayBufferを与えてモジュールの作成と関数の呼び出しを行うと、次のようなコードとなります。</p>

<p>気をつけなければならいのは、TypedArrayの大きさです。2<sup>12</sup> 以上、2<sup>24</sup>バイト未満の大きさになるようにするか、2<sup>24</sup>バイトの整数倍の大きさになるようにしてください。そうしなければ、リンクに失敗してします。</p>

<p>これが原因でリンクに失敗した場合は、コンソールに適切なサイズが表示されます。それを参考に大きさを際設定すればようでしょう。</p>

<p></p><pre class="crayon-plain-tag">const heap = new Int8Array(0x10000)
const caesar = Caesar(window, {}, heap);
heap[0] = 72; heap[1] = 65; heap[2] = 76; // HALと設定
caesar.encrypt(1); // HALが1文字ずつシフトされる</pre><p></p>

<h2>まとめ</h2>

<p>以上のように、JavaScriptと比べてasm.jsは随分と書きづらく、できることも限られています。ArrayBufferを駆使すればベクトルの計算も可能ですが、オブジェクトと平坦なArrayBufferとの相互変換を自分で実装しなくてはならず、なかなか骨が折れる作業であることは否めません。</p>

<p>その代わり得られる効果は絶大です。JITによって処理が重たくなることもなく、高速な実行が可能となります。またコンパイルされた結果はキャッシュされるため、2回目以降は高速に起動できるようになります。</p>

<p>とはいえ、手で書くのは骨が折れます。</p>

<p>「人間のやることではない」</p>

<p>「高級言語で実装したい」</p>

<p>そう思う方も多いでしょう。そのために用意されているツールがEmscriptenです。次回はEmscriptenを利用したC言語やC++で実装されたコードのasm.jsへの変換について解説します。</p>
]]></content:encoded>
		
		<series:name><![CDATA[低水準言語asm.jsとWebAssembly詳解]]></series:name>
	</item>
		<item>
		<title>Webブラウザで高速な演算を可能にする低水準言語asm.jsと、WebAssembly詳解ーJavaScript が動く仕組み</title>
		<link>/chikoski/18964/</link>
		<pubDate>Thu, 07 Jul 2016 01:35:40 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=18964</guid>
		<description><![CDATA[連載： 低水準言語asm.jsとWebAssembly詳解 (1)Webブラウザの上で動作するアプリを書くための言語、といえば何が想起されるでしょうか。Flash、Sliverlight、Java、さまざまな言語が利用さ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/asmjs/" class="series-384" title="低水準言語asm.jsとWebAssembly詳解" data-wpel-link="internal">低水準言語asm.jsとWebAssembly詳解</a> (1)</div><p>Webブラウザの上で動作するアプリを書くための言語、といえば何が想起されるでしょうか。Flash、Sliverlight、Java、さまざまな言語が利用されてきましたが、やはり今のメインストリームはJavaScriptでしょう。</p>

<p>JavaScriptはさまざまな言語の特徴を併せ持つ動的言語で、Web技術の発展とAPIの整備の結果、Virtual Reality(VR)や画像認識、DAW(Desktop Audio Workstation)といった、少し前まではネイティブでの実装しかありえなかった種類のアプリケーションもWebブラウザをランタイムとするJavaScripで実装されるようになってきました。</p>

<p>そのようなアプリの代表例がゲームでしょう。少し前までのブラウザゲームといえば、リロードを繰り返すタイプのゲームか、Flashゲーム、パズルなどの簡単なものが大半を占めていたように思います。Canvasを利用して実装されたスーパマリオやNESエミュレータなどもありましたが、いずれも実験的なものであり、また20年以上前のハードウェアで快適に動くゲームだったことを考えると、CPU時間を大量に消費する「重厚」なものではありませんでした。</p>

<p>しかし最近は重厚なゲームの開発も行われ始めています。この嚆矢は<a href="http://people.mozilla.org/~vladimir/misc/bench-new/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">BananaBread</a>でしょう。これはMozillaのエンジニアチームが開発した複数同時対戦可能なFPS(First Person Shooting)です。このようなゲームの実現が可能になったのは、WebGL、Web Workers、Web Audio API、Gamepad API、IndexedDBなどに代表されるAPIの充実もありますが、既存のJavaScriptエンジンではなしえなかった高速の演算を可能にする、低水準言語の整備のおかげでもあります。</p>

<p>この連載は4回にわたって、Webブラウザ上で動作する低水準言語であるasm.jsと、（いまのところ）そのバイナリフォーマットであるWebAssemblyについて、その設計と仕様、そして開発環境を紹介します。</p>

<h2>低水準言語asm.js</h2>

<p><a href="https://asmjs.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">asm.js</a>はMozillaが研究開発したJavaScriptのサブセットで、2013年に発表されました。現在はFirefoxとGoogle Chromeによって実装が行われ、EdgeやSafariも対応を表明しています。その特徴はなんといっても動作の高速さです。次のグラフはasm.js発表時に公開されたベンチマークの結果で、棒グラフが短ければ短いほど、処理が高速であることを意味しています。このグラフによると、ベンチマークの種類にも依存しますが、概ねCやC++によるネイティブ実装の半分程度のスピードで動作していることがわかります。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/05/cppbench.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/05/cppbench.png" alt="asm.js のベンチマーク結果。ネイティブの半分程度のスピードで動作している。" class="aligncenter size-medium wp-image-18966" srcset="/wp-content/uploads/2016/05/cppbench.png 640w, /wp-content/uploads/2016/05/cppbench-300x150.png 300w, /wp-content/uploads/2016/05/cppbench-207x104.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a>
<a href="https://kripken.github.io/mloc_emscripten_talk/cppcon.html#/24" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://kripken.github.io/mloc_emscripten_talk/cppcon.html#/24</a>より引用</p>

<p>このような高速に動作を可能にしているのは、事前コンパイルと呼ばれる技術です。AOT(Ahead of Time)とも呼ばれるこの技術を利用すると、プログラムはその実行直前にコンパイルが行われ、ネイティブコードへと変換されます。ブラウザは内蔵するコンパイラでasm.jsで書かれたコードをネイティブコードに変換し、ネイティブコードを実行することで、この高速性能を実現しているのです。</p>

<p>事前コンパイルを可能とするために、asm.jsで書かれたプログラムは以下にあげる特徴を持っています。</p>

<ul>
<li>変数や式、関数の型が静的解析可能である</li>
<li>数値計算に特化している</li>
<li>作成や属性の参照、メソッド呼出といったオブジェクトに関する操作ができない</li>
<li>利用できるコレクション型はTyped Arrayのみである</li>
</ul>

<p>一般のJavaScriptやAngular、RxJSといったモダンなフレームワークの提供するDSL(Domain Specific Language)に
慣れた身からすれば、機能が制限され、「低水準な」印象が拭えません。2013年にもなって、なぜ、このような制約の強い言語が開発されたのでしょうか。もちろんJavaScript発展の文脈に基づく、実用上の要求があるためです。それを理解するに、まずJavaScriptの動作について簡単に（かつ大雑把に）振り返ることとしましょう。</p>

<h2>JavaScriptが動く仕組み</h2>

<p>プログラミング言語は「コンパイラ型」と「インタプリタ型」の2つに分けることができます。C言語やC++は前者の典型で、
後者の典型はPerlやRuby、Pythonでしょう。JavaScriptも後者に分けられます。インタプリタ型の特徴は、あるプログラムの動作に「インタプリタ」と呼ばれる別のプログラムが必要である点です。SpiderMonkey(Firefox)、Chakra(Edge)、V8(Chrome / Node.js)はJavaScript向けのインタプリタとして有名でしょう。</p>

<p>インタプリタは、文字列を解釈してプログラムとしての文法的構造を取得します。この過程を字句解析・構文解析と呼び、
結果得られた文法的な構造のことを抽象構文木(AST: Abstract Sytactic Tree)と呼びます。例えばa=1+2*3;
のASTは次のようになります。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/05/ast.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/05/ast-238x300.png" alt="a = 1 + 2 * 3;の抽象構文木" width="178" height="225" class="aligncenter size-medium wp-image-18968" srcset="/wp-content/uploads/2016/05/ast-238x300.png 238w, /wp-content/uploads/2016/05/ast-164x207.png 164w, /wp-content/uploads/2016/05/ast.png 275w" sizes="(max-width: 178px) 100vw, 178px" /></a></p>

<p>素朴なインタプリタは、この抽象構文木を枝の方から実行していきます。先ほどの例だと、まず2 * 3の計算を行い、
その結果である6で2 * 3に相当する部分木を置き換えます。その後1 + 6を計算し、最後にa = 6を計算します。この場合では、*や+、=といった演算子や標準ライブラリ中の関数などは、インタプリタ中の関数として実装され、それらをASTを解釈する巨大なswitch文の中から呼び出してプログラムは実行されます。そしてこの巨大なswitch文は、プログラムの評価が終わるまで繰り返し実行されます。</p>

<h3>仮想マシンとバイトコード</h3>

<p>このようなインタプリタはシンプルで理解しやすいのですが、変数のスコープや返り値の受け渡しの実現が困難になりがちです。そこで多くのインタプリタはASTをバイトコードに変換して実行します。バイトコードは単なるASTのバイナリ表現ではなく、インタプリタによって実装された仮想的なハードウェア（仮想マシン）を動かすマシンコード、つまり仮想的なネイティブコードとなっています。例えば(a,b,c)=&gt;a+b*cという関数は、SpiderMonkeyによって次のようなバイトコードの列に変換されます。</p>

<p></p><pre class="crayon-plain-tag">getarg 0
getarg 1
getarg 2
mul
add
return
retrval</pre><p></p>

<p>getargやmul、addなどはSpiderMonkeyの実装している仮想マシンの持つ命令です。仮想マシンには計算に使う値をスタックに保存するスタックマシンと、レジスタに配置するレジスタマシンとがありますが、SpiderMonkeyはスタックマシンを採用しており、変数への代入や、実引数の参照はスタックに対する操作として実現されています。</p>

<p>なおSpiderMonkeyの提供するバイトコードは<a href="https://developer.mozilla.org/docs/Mozilla/Projects/SpiderMonkey/Internals/Bytecode" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちらのサイト</a>で一覧できます。</p>

<p>バイトコードに変わったとはいえ、実行のモデルは変わりません。バイトコードを1つずつとってきては、バイトコードを解釈する巨大なswitch文を通じて、各命令を実装する関数が呼ばれます。これがプログラムの実行が終了するまで繰り返されます。</p>

<h3>型情報の不足</h3>

<p>どうせネイティブコードを出力するなら、仮想マシンのネイティブコードではなく、実マシンのネイティブコードを出力すればいいのに。そう思われるのも当然ですが、出力しない、もしくはできないのにも理由があります。それらの中で大きなものの1つが、型情報の不足です。</p>

<p></p><pre class="crayon-plain-tag">function wrap(value){
  return {value: value};
}

var b1 = wrap(1);
var b2 = wrap(2);
var result = b1.value + b2.value;</pre><p></p>

<p>resultにはどういう種類のデータが入るでしょうか？数値とすぐわかる方も多いとは思います。ではなぜ数値だとわかったのでしょうか？頭の中で上記のプログラムを実行した結果、b1.valueとb2.valueの値が両方とも数値であることがわかり、
数値同士の加算は数値になることから、resultには数値が代入されると結論づけたのではないでしょうか。</p>

<p>では、このwrapの返り値のvalue属性には常に数値が代入されているでしょうか？wrapの引数は数値でなければならない、とはどこにも書いてありません。そのため、次のような呼び出しも可能です。</p>

<p></p><pre class="crayon-plain-tag">var b3 = wrap("abcd");
var b4 = wrap({id: 1234});
var b5 = wrap(null);
var b6 = wrap(undefined);</pre><p></p>

<p>b3,b4,5,b6それぞれのvalue属性の型も、string,object,null,undefinedと異なる型になっています。
このようにJavaScriptのプログラムは実行するまで変数や演算結果の型がわからないことが多々あります。
これはプログラムの中に型の情報が含まれていないためです。
もし型情報が含まれていれば、実行しなくても変数や演算の結果の型を決められます。
型付けの強い言語の代表例であるRustを使って同様のプログラムを記述すると、次のようになります：</p>

<p></p><pre class="crayon-plain-tag">struct Box&lt;T&gt;{value: T}
fn wrap&lt;T&gt;(value:T) -&gt; Box&lt;T&gt;{
  Box{value: value}
}
fn main() {
  let b1 = wrap(1);
  let b2 = wrap(2);
  let result = b1.value + b2.value;
  println!("result = {}", result);
}</pre><p></p>

<p>このプログラムでは実行しなくても、resultの型はintであることがわかります。resultの宣言からは、型宣言を省略してあります。それでもRustの処理系は他の情報から型を決定して型を決めています。それはBoxとwrapの宣言についている型情報、そしてwrapを呼び出した際の引数から、b1.valueとb2.valueの型が決定できるためです。</p>

<p>さて型がわからないことが、ネイティブコードの出力にどのような影響を与えるのでしょうか。それは端的にいえば、出力するネイティブコードが冗長になるということです。例えばIntelのCPUの場合、加算だけでも20種類以上の命令があります。
これはデータ型と、データの保存場所によって使用する命令が異なるからです。データ型が適切に決定できているなら、使用する命令を1つに絞ることができます。</p>

<p>しかしデータ型を適切に決定できない場合、その可能性を1つずつチェックし、そのチェックした結果に合わせて使用する命令を決めるといったようなコードを出力せざるをえません。その結果コード全体は冗長になり、スピードもあまりでなくなってしまいます。ネイティブコードの出力にも時間がかかるため、その時間に見合った効果が得にくくなってしまいます。</p>

<h3>JITコンパイル</h3>

<p>ネイティブコードを出力したいが、ソースコードには型に関する情報がない。この状況を打破するために利用されている技術がJIT(Just in Time)コンパイルです。これはJavaScriptをいきなり高速に動かすためのネイティブコードに変換せず、しばらくインタプリタなどで動作させます。変数に代入される値を観察して、その型に関する統計情報を集めます。</p>

<p>この統計情報と、1つの変数には同じ種類のデータが代入される傾向にある、というヒューリスティックを利用してその変数の型を推定していきます。推定がある程度できた時点で、該当するコードからネイティブコードを出力します。このようにプログラムを動かしながら、必要に応じてネイティブコードへと出力するのがJITです。</p>

<p>SpiderMonkeyではJITは2段階に分かれています。まずはnullチェックなどを含んだ冗長なコードを出力するベースラインJIT を行います。その状態でしばらく動作させ、型情報の統計を取得します。ある程度の型情報が集まったところで、その情報を元により効率の良いコンパイルを行います。</p>

<p>図中のIon compileがそれです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/05/jit-diagram.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/05/jit-diagram.png" alt="SpiderMonkeyにおけるJITコンパイルの流れ。" class="aligncenter size-medium wp-image-18969" srcset="/wp-content/uploads/2016/05/jit-diagram.png 640w, /wp-content/uploads/2016/05/jit-diagram-300x77.png 300w, /wp-content/uploads/2016/05/jit-diagram-207x53.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a>
<a href="https://blog.mozilla.org/luke/2014/01/14/asm-js-aot-compilation-and-startup-performance" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">asm.js AOT compilation and startup performance</a>より引用</p>

<p>型情報が集まったかどうかは実行回数によって決まっているようです。コードをざっと眺めた限り、10回程度繰り返し実行されるかどうかが、コンパイルを行うかどうかの判断の目安になっているようです。</p>

<p>上図のように、コンパイルされたコードは常に維持されるわけではありません。ときにはbail、つまりコンパイル結果を捨てて、もう一度型の推定からやり直します。これはJavaScriptの関数呼び出しに型による制約がかけられず、推定がヒューリスティックによるもののため、仕方がないことです。例えば、次のような呼び出しが行われた場合twiceのコンパイル結果は捨てられてしまいます。</p>

<p></p><pre class="crayon-plain-tag">function twice(a){
  return a + a;
}
var array = [0, 1, 2, 3, ... , 100000].map(twice);
var str = twice("こんにちは");</pre><p></p>

<p>map関数からの呼び出しによってtwiceは10000回実行されます。この途中で（正確には、行われるかどうかは処理系に依存するのですが）、twiceはnumberを引数にとり、numberを返す関数としてJITコンパイルされます。しかし次の行の引数に文字列が与えられた呼び出しによって、その結果は捨てられてしまいます。捨てないとこの処理が行えないためです。</p>

<p>TypeScriptのような型制約があればこのようなことが起きないのですが、残念ながらJavaScriptにはそれがありません。
そのため時には時間をかけて行ったコンパイル結果を捨て、低速に動くことを余儀なくされてしまいます。</p>

<h2>まとめ</h2>

<p>JITを利用することで、よく利用されるコードを高速に動作させられるようになりました。
それでも次のような問題が残っています。</p>

<ol>
<li>よく使うコードしかネイティブコードにならない</li>
<li>高速に動作するようになるまでにはリードタイムが必要</li>
<li>型の推定には失敗することがある</li>
</ol>

<p>重厚なゲームのようなアプリケーションの場合、2や3の問題は致命的なものとなりえます。</p>

<p>FPS(First Person Shooting)で対戦している場合を想像してみてください。対戦の最初はコンパイルがすんでいないため、ゲームはもっさりと動作しています。これではゲームになりません。しばらくは自分の陣地でゆっくりしてコンパイルが終わるのを待ちましょう。コンパイルが終わってFPS(Frame Per Second)が出てきました。ようやく本当のゲーム開始です。</p>

<p>そこで相手の攻撃を読み、侵攻して、草むらに潜み、相手がくるの待ち受けます。いざ相手へ攻撃をかけようとした瞬間、3に起因するコードの再コンパイルが発生し、画面がプチフリーズ。ゲームに復帰したら、目の前には銃を構える敵が…</p>

<p>こういう状況を避けるためにも、上述したような問題に対する回避策が求められました。それがAOTとasm.jsでした。AOTによって1,2の問題を回避し、その実現と3の回避のために型情報のふくまれたasm.jsが導入されることとなりました。</p>

<p>次回はasm.jsがどのように型情報を与えていくのか、型アノテーションを中心に解説します。</p>
]]></content:encoded>
		
		<series:name><![CDATA[低水準言語asm.jsとWebAssembly詳解]]></series:name>
	</item>
		<item>
		<title>HTMLとJavaScript、CSSだけで作ろう！Firefox OSアプリ</title>
		<link>/chikoski/13697/</link>
		<pubDate>Thu, 16 Apr 2015 03:00:15 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=13697</guid>
		<description><![CDATA[連載： HTML5 Conference 2015 特集 (5)こんにちは、清水です。先日のHTML5 ConferenceでFirefox OS上で動作するアプリの開発と、Firefox Marketplaceの公開に...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/h5conf2015/" class="series-257" title="HTML5 Conference 2015 特集" data-wpel-link="internal">HTML5 Conference 2015 特集</a> (5)</div><p>こんにちは、清水です。先日のHTML5 ConferenceでFirefox OS上で動作するアプリの開発と、Firefox Marketplaceの公開に関する講演をさせていただきました。今回はその講演内容のうち、アプリ作成に関する部分を重点的に説明します。</p>

<h2>すべてWeb技術で</h2>

<p>Firefox OSの特徴は、ユーザの目にする部分は全てHTML5で実装されている点にあります。音楽アプリ、カメラ、ギャラリーといったプリインストールされているものはもちろん、ダイヤラーや、SMS、スマホのロックスクリーンや、ホーム画面といったシステムよりのアプリもすべてHTMLとJavaScript、CSSだけで実装されています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/01-html5.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/01-html5-300x225.png" alt="Firefox OSのアプリ、UIはWeb技術のみでできています" width="300" height="225" class="aligncenter size-medium wp-image-13700" srcset="/wp-content/uploads/2015/03/01-html5-300x225.png 300w, /wp-content/uploads/2015/03/01-html5.png 640w, /wp-content/uploads/2015/03/01-html5-207x155.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>Firefoxをインストールして、開発スタート</h2>

<p>Firefox OSのアプリ開発に必要なことはただ一つ、Firefoxのインストールです。開発者アカウントの作成も、ディベロッパープログラムへの登録も、専用SDKのインストールも必要ありません。</p>

<p>FirefoxにはWebIDEという機能があります。これはアプリ開発ツールとして必要な機能を一通り持っています：</p>

<ul>
<li>ファイルの作成・編集機能、シンタックスハイライト</li>
<li>デバッガ、インスペクタ</li>
<li>シミュレータの起動、</li>
<li>実機との接続管理、アプリの転送機能</li>
</ul>

<p>リリース版のFirefoxでも十分開発に耐えますが、開発をするなら <a href="https://www.mozilla.org/firefox/developer/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Developer Edition</a>の利用をお勧めします。Mozillaの提供する開発者向けの機能をいち早く利用できる点が特徴です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/02-fireox-developer-edition.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/02-fireox-developer-edition-300x210.png" alt="Firefox Developer Editionの起動画面" width="300" height="210" class="aligncenter size-medium wp-image-13699" srcset="/wp-content/uploads/2015/03/02-fireox-developer-edition-300x210.png 300w, /wp-content/uploads/2015/03/02-fireox-developer-edition.png 640w, /wp-content/uploads/2015/03/02-fireox-developer-edition-207x145.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>Firefox Developer Editionは、リリース版とは異なる場所にインストールされます。また初回起動時に開発用のプロファイルを作成するため、リリース版との併用が可能です。<a href="https://mozilla.org/firefox/sync/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Sync</a>を利用して同期しておけば、ブックマークや履歴、パスワードは通常利用しているものと共有できます。</p>

<h2>Hello World!</h2>

<p>ではさっそく、WebIDEを利用してHello Worldしてみましょう。Firefoxのメニューから「Web 開発」→「Web IDE」と進んでWeb IDEを起動します。起動すると次のような画面が表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/04-webide.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/04-webide-300x241.png" alt="04-webide" width="300" height="241" class="aligncenter size-medium wp-image-14196" srcset="/wp-content/uploads/2015/03/04-webide-300x241.png 300w, /wp-content/uploads/2015/03/04-webide.png 640w, /wp-content/uploads/2015/03/04-webide-207x167.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>画面の左上にある「アプリを開く」をクリックすると展開されるメニューから「新規アプリ」を選びます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/05-newapp.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/05-newapp-300x145.png" alt="05-newapp" width="300" height="145" class="aligncenter size-medium wp-image-14197" srcset="/wp-content/uploads/2015/03/05-newapp-300x145.png 300w, /wp-content/uploads/2015/03/05-newapp.png 640w, /wp-content/uploads/2015/03/05-newapp-207x100.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>選ぶとテンプレートの選択を求められます。「HelloWorld」テンプレートを選び、プロジェクト名にアプリの名前を入力して、「OK」ボタンを押すとアプリのテンプレートが作成されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/06-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/06-helloworld-300x232.png" alt="HelloWorldテンプレートを利用して新規にアプリを作成する例" width="300" height="232" class="aligncenter size-medium wp-image-14198" srcset="/wp-content/uploads/2015/03/06-helloworld-300x232.png 300w, /wp-content/uploads/2015/03/06-helloworld.png 640w, /wp-content/uploads/2015/03/06-helloworld-207x160.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>シミュレータのインストール</h2>

<p>次にシミュレータをインストールします。シミュレータはブラウザのアドオンとして提供されています。画面右上のメニューから「シミュレータをインストール」を選び、表示された画面の中から開発を行う Firefox OSのバージョンに合わせたシミュレータをインストールします。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/07-simulator-installation.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/07-simulator-installation-300x232.png" alt="シミュレータのインストール画面" width="300" height="232" class="aligncenter size-medium wp-image-14199" srcset="/wp-content/uploads/2015/03/07-simulator-installation-300x232.png 300w, /wp-content/uploads/2015/03/07-simulator-installation.png 640w, /wp-content/uploads/2015/03/07-simulator-installation-207x160.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>KDDIから販売されているFirefox OS端末、Fx0はFirefox OS 2.0で動作しています。国内向けにアプリを書く場合は、Firefox OS 2.0のシミュレータをインストールするとよいでしょう。</p>

<h2>アプリの起動と修正の反映</h2>

<p>作成したテンプレートを、インストールしたシミュレータ上で実行します。WebIDE上部にある「実行ボタン」を押すと、実行できます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/08-app-execution.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/08-app-execution-300x75.png" alt="08-app-execution" width="300" height="75" class="aligncenter size-medium wp-image-14200" srcset="/wp-content/uploads/2015/03/08-app-execution-300x75.png 300w, /wp-content/uploads/2015/03/08-app-execution.png 640w, /wp-content/uploads/2015/03/08-app-execution-207x52.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>実行すると、次のような画面が表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/09-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/09-helloworld-180x300.png" alt="09-helloworld" width="180" height="300" class="aligncenter size-medium wp-image-14201" srcset="/wp-content/uploads/2015/03/09-helloworld-180x300.png 180w, /wp-content/uploads/2015/03/09-helloworld.png 385w, /wp-content/uploads/2015/03/09-helloworld-125x207.png 125w" sizes="(max-width: 180px) 100vw, 180px" /></a></p>

<p>このテンプレートでは、起動時にindex.htmlが表示されます。これを次のように修正します。</p>

<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"&gt;
    &lt;title&gt;Hello World&lt;/title&gt;
    &lt;link rel="stylesheet" href="app.css"&gt;
    &lt;script src="app.js" defer&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;こんにちは世界！&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>また、app.jsを次のように修正すると、アプリのロードが終了した時点でアラートダイアログが表示されます。</p>

<p></p><pre class="crayon-plain-tag">window.addEventListener("load", function() {
  alert("Hello World!");
});</pre><p></p>

<p>WebIDEの実行ボタンをもう一度押すと、これらの修正が実行中のアプリに反映されます。</p>

<h2>アプリの構造</h2>

<p>テンプレートに従って作成されるファイルは以下のような構造をしています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/03-files-of-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/03-files-of-helloworld-300x251.png" alt="Hello World テンプレートによって展開されたファイル" width="300" height="251" class="aligncenter size-medium wp-image-13698" srcset="/wp-content/uploads/2015/03/03-files-of-helloworld-300x251.png 300w, /wp-content/uploads/2015/03/03-files-of-helloworld-207x173.png 207w, /wp-content/uploads/2015/03/03-files-of-helloworld.png 600w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>HTMLやJavaScriptに加えて、&#8221;manifest.webapp&#8221;というファイルがあります。これはアプリに関するメタデータで、これはアプリのインストールや、Mozillaの提供するアプリストアであるFirefox Maretplaceにアプリを登録時に参照されます。</p>

<p>manifest.webappの実体は次のようなJSONファイルです。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "こんにちは世界",
  "description": "A Hello World app",
  "launch_path": "/index.html",
  "icons": {
    "16": "/icons/icon16x16.png",
    "48": "/icons/icon48x48.png",
    "60": "/icons/icon60x60.png",
    "128": "/icons/icon128x128.png"
  },
  "type": "privileged",
  "permissions": {}
}</pre><p></p>

<p>各項目の詳細については、<a href="https://developer.mozilla.org/Apps/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Networkのアプリマニフェスト</a>
をご覧いただくのが確実ですが、上記の例にある項目は以下のような意味を持ちます。</p>

<table>
<thead>
<tr>
  <th>項目名</th>
  <th>説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td>name</td>
  <td>人間が読むための、アプリ名。最長 128 文字</td>
</tr>
<tr>
  <td>description</td>
  <td>人間のためのアプリ説明文。最長 1024 文字</td>
</tr>
<tr>
  <td>launch_path</td>
  <td>アプリ起動時に読み込まれるHTMLファイルのパス。上記の例では、manifest.webappと同じフォルダにあるindex.htmlが読み込まれる</td>
</tr>
<tr>
  <td>icons</td>
  <td>アイコンのリスト。128ピクセルx128ピクセルのアイコンは必須。また 512ピクセルx512ピクセルのものも含めることが推奨されている</td>
</tr>
<tr>
  <td>type</td>
  <td>アプリの種別。特権アプリの場合は、privilegedと記入する。一般アプリの場合は省略可能だが、明示する場合はwebと記入する</td>
</tr>
<tr>
  <td>permissions</td>
  <td>Camera APIやDevice Storage APIのように、注意が必要なAPIを利用する場合は、ここに列挙する</td>
</tr>
</tbody>
</table>

<p>以上のように、HTML、CSS、JavaScriptにmanifest.webappを足したものが、Firefox OSアプリの最小構成となります。</p>

<h2>Firefox OS で利用できる API</h2>

<p>Firefox OS のアプリは、すべてJavaScriptで記述します。そのため カメラやGPSといったセンサー類へのアクセスや、バイブのコントロール、SDカードへのデータ保存などは、HTML5で利用できるAPIを通して行います。利用できるAPIの一部分を挙げると、以下のようになります。</p>

<ul>
<li>Ambient Light Sensor API：環境光センサーを利用して周囲の照度を取得できる</li>
<li>Geolocation API：端末の物理的な位置を取得できる</li>
<li>Vibration API：ゲームなどのフィードバックのために、バイブレーションをコントロールできる</li>
<li>Camera：デバイスに内蔵されたカメラを利用して動画や、写真を撮影できる</li>
<li>Contacts：連絡先データベースへのアクセスが可能になる</li>
<li>Device Storage：SD カードなど、端末の持つストレージに対して読み書きが行える</li>
</ul>

<p>例えばDevice Storage APIを利用して、SDカード中のファイルをすべてコンソールに出力するプログラムは、次のようになります。</p>

<p></p><pre class="crayon-plain-tag">var sdcard = navigator.getDeviceStorage("sdcard");
var cursor = sdcard.enumerate();
cursor.onsuccess = function(){
  var file = this.result;
  console.log(file.name);
  if(!this.done){
    this.continue();
  }
};</pre><p></p>

<h2>WebActivities：アプリの機能を利用する API</h2>

<p>音楽のライブラリや、写真のギャラリー、カメラでの撮影といった機能を実装する方法は2つあります。1つは上記にあげたAPIを利用して1から機能を作る方法、もう1つはWebActivitiesを利用して他のアプリを呼び出す方法です。</p>

<p>標準でインストールされている音楽アプリや、ギャラリー、カメラアプリは、「ライブラリから音楽の選択する」「ギャラリーから写真を選ぶ」「写真を撮る」といったアプリの機能の一部を他のアプリから利用できるようになっています。</p>

<p>これを利用しているアプリの例には、<a href="https://marketplace.firefox.com/app/cameran" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Cameran</a> があります。Cameranは写真にフィルタや効果を追加するアプリなのですが、自分で写真撮影や管理機能を実装しているのではなく、インストールされている他のアプリの提供する「画像を選ぶ機能」を利用しています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/10-webactivities.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/10-webactivities-169x300.png" alt="10-webactivities" width="169" height="300" class="aligncenter size-medium wp-image-14203" srcset="/wp-content/uploads/2015/03/10-webactivities-169x300.png 169w, /wp-content/uploads/2015/03/10-webactivities.png 360w, /wp-content/uploads/2015/03/10-webactivities-116x207.png 116w" sizes="(max-width: 169px) 100vw, 169px" /></a></p>

<p>他のアプリが提供している機能を、自分のアプリから呼び出して利用するためのAPIが、WebActivitiesです。例えば、他のアプリが提供するJPEG形式の画像を選択する機能の呼び出しは、次のようにWebActivitiesを利用して実現できます。</p>

<p></p><pre class="crayon-plain-tag">var activity = new MozActivity({
  name: "pick",
  data: {
    type: "image/jpeg"
  }
});
activity.onsuccess = function() {
  var picture = this.result;
  console.log("A picture has been retrieved");
};</pre><p></p>

<p>尚、WebActivitiesを利用して呼び出せるのは機能の名前であって、アプリではありません。おなじ名前の機能が複数のアプリから提供されている場合、どのアプリを利用するかはユーザの選択に任されます。</p>

<p>WebActivitiesの詳細、特に標準でインストールされているシステムアプリが提供する機能名については、<a href="https://developer.mozilla.org/docs/Web/API/Web_Activities" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Network の Web アクティビティ</a>をご覧ください。</p>

<h2>アプリケーションの権限</h2>

<p>上記のAPIすべてを、アプリから利用できるわけではありません。強力なAPIの利用には、それに見合った権限が必要となります。</p>

<p>Firefox OSのアプリは権限に応じて次の3つに分類されます。</p>

<ul>
<li>一般のアプリ (type:web)</li>
<li>特権アプリ (type: privileged)</li>
<li>内部アプリ (type: certified / internal)</li>
</ul>

<p>最後の内部アプリ、以前は認定アプリ (Certified App)と呼ばれていたアプリは、キャリアもしくはそれに準じるベンダしか作成を許されていません。そのため私たちが作成するアプリは、一般アプリもしくは特権アプリのどちらかになります。</p>

<p>権限と、利用できるAPIの対応関係は、OSのバージョンによって異なります。対応関係はWebIDEの「許可設定一覧」で確認できます。</p>

<p>許可設定一覧は以下のようになっています。</p>

<p>✓は利用可能、✕ は不可能、! は利用可能だが利用時にユーザに対して通知されることを表しています。</p>

<p>以下の例では、Camera APIを利用するためには、アプリを特権アプリとしなければならないことがわかります。</p>

<table>
<thead>
<tr>
  <th>名前</th>
  <th>type:web</th>
  <th>type:privileged</th>
</tr>
</thead>
<tbody>
<tr>
  <td>geolocation</td>
  <td>!</td>
  <td>!</td>
</tr>
<tr>
  <td>camera</td>
  <td>✕</td>
  <td>!</td>
</tr>
<tr>
  <td>alarms</td>
  <td>✓</td>
  <td>✓</td>
</tr>
</tbody>
</table>

<h2>実際に作ってみよう</h2>

<p>以上がFirefox OSアプリの概要でした。これを踏まえて、ボイスレコーダーアプリの作成を例に、アプリの作成例をみてみましょう。</p>

<p>今回作成するアプリは次のような1画面のアプリとなります。画面をタップすると録音を開始し、もう1度のタップで録音を終了します。録音した音声は ogg ファイルとして音楽ライブラリに保存されるものとします。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/11-recorder.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/11-recorder-169x300.png" alt="作成するボイスレコーダーアプリの実行画面" width="169" height="300" class="aligncenter size-medium wp-image-14202" srcset="/wp-content/uploads/2015/03/11-recorder-169x300.png 169w, /wp-content/uploads/2015/03/11-recorder.png 360w, /wp-content/uploads/2015/03/11-recorder-116x207.png 116w" sizes="(max-width: 169px) 100vw, 169px" /></a></p>

<p>なお今回作成したサンプルは、 <a href="https://gist.github.com/chikoski/00bbcb2cff65293869a0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">gist</a>で公開しています。
こちらもご利用ください。</p>

<h2>使用するAPIとアプリの権限</h2>

<p>今回は次のAPIを利用します。</p>

<table>
<thead>
<tr>
  <th>API名</th>
  <th>目的</th>
  <th>Firefox OS 2.0で必要な権限</th>
</tr>
</thead>
<tbody>
<tr>
  <td>GetUserMedia</td>
  <td>マイクからの音声入力を扱うため</td>
  <td>通常</td>
</tr>
<tr>
  <td>MediaRecorderAPI</td>
  <td>音声を録音するため</td>
  <td>通常</td>
</tr>
<tr>
  <td>Web Audio API</td>
  <td>音声の分析を行うため</td>
  <td>通常</td>
</tr>
<tr>
  <td>DeviceStorage API</td>
  <td>音声をファイルとして保存するため</td>
  <td>特権</td>
</tr>
</tbody>
</table>

<p>DeviceStorage APIを利用するためには、アプリの種別を特権アプリとする必要があります。またいくつかのAPIを利用するためには、manifest.webappのpermissionsの項目に記述を行う必要があります。そのため manifest.webappを以下のように記述します。typeと permissionsの項目が、それぞれ設定されていることを確認してください。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "audio-caputre-sample",
  "description": "An sample app to capture audio through microphone",
  "launch_path": "/index.html",
  "icons": {
    "16": "/icons/icon16x16.png",
    "48": "/icons/icon48x48.png",
    "60": "/icons/icon60x60.png",
    "128": "/icons/icon128x128.png"
  },
  "type": "privileged",
  "permissions": {
    "audio-capture": {
      "description": "To record audio"
    },
    "device-storage:music": {
      "description": "To store captured audio",
      "access": "readwrite"
    }
  }
}</pre><p></p>

<h2>HTML と CSS の記述</h2>

<p>アプリのビューは HTML と CSS で定義します。今回のアプリでは次のものを利用しました。</p>

<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"&gt;
    &lt;title&gt;audio capture test&lt;/title&gt;
     &lt;script src="app.js" defer&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="app.css"&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;canvas id="canvas"&gt;&lt;/canvas&gt;
    &lt;p id="recording"&gt;●REC&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>CSS は以下のようになっています。</p>

<p></p><pre class="crayon-plain-tag">body{
   margin: 0;
   padding: 0;
 }
 #canvas{
   width: 100%;
   height: 400px;
   margin: 0;
   padding: 0;
   box-sizing: border-box;
 }
 #recording{
   color: red;
   position: fixed;
   top: .5em;
   left: .5em;
   display: none;
 }</pre><p></p>

<h2>JavaScript を使った録音</h2>

<p>コードの全体像は <a href="https://gist.github.com/chikoski/00bbcb2cff65293869a0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">gist に公開したもの</a>をご覧いただくこととして、
ここではマイクからの入力ストリームの取得、録音、そしてファイルへの出力部分について解説します。</p>

<p>まずは、マイクからの入力ストリームの取得方法です。manifest.webapp中のpermissionsの項目に&#8221;audio-capture&#8221;を追加すると、
つぎのようにGetUserMediaを使っ、てマイクからの入力を扱うための入力ストリームを取得できます。</p>

<p></p><pre class="crayon-plain-tag">navigator.getUserMedia({video: false, audio: true}, 
                       streamAquired, 
                       error =&gt;{
                         console.log(error);
                       });</pre><p></p>

<p>この実行が成功すると、コールバック関数が呼ばれます。取得した入力ストリームは、関数の第1引数として与えられます。上記の例では streamAquired という関数が呼ばれます。この関数は入力ストリームを利用する様々なオブジェクトの初期化を行います。</p>

<p>ここで初期化されるオブジェクトの中には MediaRecorder オブジェクトがあります。初期化は次の様に行われています。</p>

<p></p><pre class="crayon-plain-tag">var initRecorder = function(stream){
  recorder = new MediaRecorder(stream);
  recorder.ondataavailable = (event) =&gt; {
    console.log(event); 
    if(storage != null){
      var filename = createFileName(event);
      console.log("attempt to save as " + filename);
      var req = storage.addNamed(event.data, filename);
      req.onsuccess = function(){
        console.log("saved as " + this.result);
      };
      req.onerror = function(){
        console.log(this.error.name);
      };
    }
  };
};</pre><p></p>

<p>MediaRecorderオブジェクトは、その名の通りメディアデータの記録を行うオブジェクトです。startメソッドを実行すると記録を開始し、stopメソッドを実行すると記録を停止し、記録したデータを用意します。データの用意できると、dataavailableイベントが発生します。用意されたデータは、dataavailableのdata属性でBlobとして参照できます。</p>

<p>上記の例では取得したBlobオブジェクトを、DeviceStorage APIのaddNamedメソッドを使って保存をしています。ここで利用しているstorageオブジェクトは次の様に作成されています。</p>

<p></p><pre class="crayon-plain-tag">var storage = navigator.getDeviceStorage("music");</pre><p></p>

<p>これは音楽データ用のストレージを取得しています。取得できるストレージの種類は次の4種類です。これ以外にもappsというアプリ用ストレージがありますが、これはシステムアプリからのみアクセスが許可されており、我々の作成するアプリは操作できません。</p>

<table>
<thead>
<tr>
  <th>ストレージ名</th>
  <th>役割</th>
</tr>
</thead>
<tbody>
<tr>
  <td>music</td>
  <td>音楽データ用ストレージ</td>
</tr>
<tr>
  <td>pictures</td>
  <td>写真データ用ストレージ</td>
</tr>
<tr>
  <td>videos</td>
  <td>動画データ用ストレージ</td>
</tr>
<tr>
  <td>sdcard</td>
  <td>汎用データストレージ</td>
</tr>
</tbody>
</table>

<p>取得したストレージに対してメソッド呼び出しを行うと、DOMRequestオブジェクトを返します。このオブジェクトのonsuccess属性やonerror属性に関数を登録することで、その操作が成功したか、失敗したかを知ることができます。上記の例では単に成否をログに出力しているだけですが、エラー処理が必要な場合などは、こちらにその処理を記述することになります。</p>

<h2>気軽に作ろう！</h2>

<p>以上 Firefox OSアプリの構成と作成方法について概観しました。</p>

<p>Firefox OSに向けたアプリの作成についてまとめると、次の3点になるかと思います。</p>

<ul>
<li>Firefoxがあれば開発をはじめられる</li>
<li>Firefox OSアプリ = HTML + JS + CSS + manifest.webapp </li>
<li>ライブラリの追加なしで、ハードウェアをコントロールできる</li>
</ul>

<p>とにかく開発を始めるための敷居が低く、HTMLや CSS、JavaScriptといったWeb標準技術のみで、ハードウェアへアクセスし、コントロールするようなアプリが作れます。</p>

<p>しかもブラウザエンジンがOSに組み込まれているため、作成したアプリのコンパイルやビルドが必要ありません。Webページを作るように、修正したアプリを再読み込みして即座に実行できます。また本文中では解説しませんでしたが、実機へのアプリの転送やデバッグもシミュレータと同様の手順で行えます。</p>

<p>このように開発の敷居が低く、簡単にアプリを作り始められるFirefox OSで、みなさんも作る自由を謳歌してください。</p>

<p>当日のセッションの動画・スライドは、こちらからご覧ください。</p>

<div class="aligncenter">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe width="560" height="315" src="https://www.youtube.com/embed/zi4u7eMfmKY" frameborder="0" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>

</div>

<p><a href="https://www.youtube.com/watch?v=zi4u7eMfmKY" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Youtube</a> /
<a href="http://www.slideshare.net/chikoski/firefox-os-43867933" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Slideshare</a></p>

<h2>参考資料</h2>

<ul>
<li><a href="https://www.mozilla.org/firefox/developer" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Developer Edition</a></li>
<li><a href="https://mozilla.org/firefox/os/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox OS</a></li>
<li><a href="https://developer.mozilla.org/Apps" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Networkのアプリセンター</a></li>
<li><a href="https://developer.mozilla.org/docs/WebAPI" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">WebAPI</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Navigator/getUserMedia" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">GetUserMedia</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Device_Storage_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">DeviceStorage API</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/MediaRecorder_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MediaRecorder API</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Web_Audio_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web Audio API</a></li>
<li><a href="https://developer.mozilla.org/Apps/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">アプリマニフェスト</a></li>
</ul>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2015 特集]]></series:name>
	</item>
		<item>
		<title>Firebugだけじゃないぞ、Firefoxの開発ツール入門</title>
		<link>/chikoski/6671/</link>
		<pubDate>Mon, 19 May 2014 03:25:38 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Firebug]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[開発ツール]]></category>

		<guid isPermaLink="false">/?p=6671</guid>
		<description><![CDATA[連載： Mozilla Japan直伝、Firefoxを使いこなす！ (1)Firefoxで使えるWeb開発用のツールといえば、Firebugが有名です。FirebugはFirefoxのアドオンとして提供されており、利用...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/firefox-dev/" class="series-164" title="Mozilla Japan直伝、Firefoxを使いこなす！" data-wpel-link="internal">Mozilla Japan直伝、Firefoxを使いこなす！</a> (1)</div><p>Firefoxで使えるWeb開発用のツールといえば、Firebugが有名です。FirebugはFirefoxのアドオンとして提供されており、利用するためには追加のインストールが必要です。ところで、インストールの必要がない開発ツールがFirefoxに付属していることをご存知でしたか？</p>

<p>今回から3回にわたって、Firefoxに標準付属の開発ツールをご紹介します。初回は開発ツールの持っている機能を概観します。</p>

<h2>起動方法</h2>

<p>まずは起動方法からご説明します。画面の左上にあるハンバーガーアイコンをクリックして表示されるメニューの中に開発ツールがあります。これをクリックすると、メニューがスライドします。この中から「開発ツールを表示」を選ぶと開発ツールが起動します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/menu.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/menu-159x300.png" alt="メニューから開発ツールを選ぶことで起動できる。" width="159" height="300" class="aligncenter size-medium wp-image-6674" srcset="/wp-content/uploads/2014/05/menu-159x300.png 159w, /wp-content/uploads/2014/05/menu-109x207.png 109w, /wp-content/uploads/2014/05/menu.png 339w" sizes="(max-width: 159px) 100vw, 159px" /></a></p>

<p>起動すると以下のような画面が表示されます。上部にあるタブを切り替えることで、個々の機能を利用できます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/devtool.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/devtool-300x179.png" alt="開発ツール起動時の画面" width="300" height="179" class="aligncenter size-medium wp-image-6673" srcset="/wp-content/uploads/2014/05/devtool-300x179.png 300w, /wp-content/uploads/2014/05/devtool-1024x613.png 1024w, /wp-content/uploads/2014/05/devtool-207x123.png 207w, /wp-content/uploads/2014/05/devtool.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>タブの左右にはいくつかのボタンが配置されています。設定に関するものは左側、機能に関するものは右側にまとめられています。</p>

<h2>開発ツールの持つ機能</h2>

<p>開発ツールはさまざまな機能を持っています。</p>

<table>
  <thead>
    <tr><th>カテゴリ</th><th>機能</th></tr>
  </thead>
  <tbody>
    <tr><td>コンテンツの作成</td><td>スクラッチパッド,スタイルエディタ</td></tr>
    <tr><td>調査とデバッグ</td><td>Webコンソール,ページインスペクタ,JavaScriptデバッガ,ネットワークモニタ,開発ツールバー,3Dビュー</td></tr>
    <tr><td>モバイル開発</td><td>アプリマネージャ,Firefox OSシミュレータ,レスポンシブデザインビュー,リモートデバッガ</td></tr>
    <tr><td>パフォーマンスチューニング</td><td>JavaScript プロファイラ,Paint Flashing Tool,リフローイベントのログ記録,ネットワークパフォーマンス</td></tr>
  </tbody>
</table>

<p>上記の機能の中から、今回は代表的なもの4つを取り上げ、簡単にご紹介します。</p>

<h2>ページインスペクタ</h2>

<p>開発ツールで必要とされる機能といえば、まずDOMのインスペクタです。「インスペクタ」と書かれたタブをクリックすることで、表示できます。</p>

<p>DOMツリーの表示、適用されているCSSの表示、計算済みの値の一覧といった基本的なことはもちろんできます。ボックスの幅や高さ、マージンといったサイズに関する情報は「ボックスモデル」として確認できます。ボックスモデルは開発ツールの中で見ることもできます。また描画されたページにオーバレイする形でも表示されます（2014年5月の時点ではベータ版で利用可能）。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/inspector-boxmodel.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/inspector-boxmodel-300x192.png" alt="ボックスモデルが描画結果にオーバレイ表示されている" width="300" height="192" class="aligncenter size-medium wp-image-6676" srcset="/wp-content/uploads/2014/05/inspector-boxmodel-300x192.png 300w, /wp-content/uploads/2014/05/inspector-boxmodel-1024x658.png 1024w, /wp-content/uploads/2014/05/inspector-boxmodel-207x132.png 207w, /wp-content/uploads/2014/05/inspector-boxmodel.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>使用されているフォントや、色が実際に目で見て確認できるというのも、細かいことながら便利な機能です。色サンプルをクリックすることで、カラーピッカーが表示されます。カラーピッカーで選んだ色が、ページの描画結果へ動的に反映されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/inspector-colorpicker.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/inspector-colorpicker-300x225.png" alt="カラーピッカーで色を選択している" width="300" height="225" class="aligncenter size-medium wp-image-6683" srcset="/wp-content/uploads/2014/05/inspector-colorpicker-300x225.png 300w, /wp-content/uploads/2014/05/inspector-colorpicker-207x155.png 207w, /wp-content/uploads/2014/05/inspector-colorpicker.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>スタイルエディタ</h2>

<p>ページの描画結果を確認しながら、要素やスタイルを編集できるのがFirefoxの大きな特徴です。その特徴がよく現れているツールがスタイルエディタです。CSS向けのエディタですが、編集内容が表示中のページの描画結果へ即座に反映されます。</p>

<p>コード補完も強力です。CSSのプロパティだけでなく、whiteやblackといった値も文脈に応じて補完します。またセレクタも補完します。タグ名はもちろんですが、表示しているページのid属性値やclass属性値などを使ってセレクタを補完できます。　</p>

<p>編集結果はファイルへ出力できます。既にあるCSSファイルを、レンラリング結果を見ながら修正しファイルへ出力、といった流れでスタイルの修正が効率的に行えます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/styleeditor-autocompletion.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/styleeditor-autocompletion-300x206.png" alt="CSSの属性、値、セレクタが自動補完される" width="300" height="206" class="aligncenter size-medium wp-image-6682" srcset="/wp-content/uploads/2014/05/styleeditor-autocompletion-300x206.png 300w, /wp-content/uploads/2014/05/styleeditor-autocompletion-207x142.png 207w, /wp-content/uploads/2014/05/styleeditor-autocompletion.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>Webコンソール</h2>

<p>ページインスペクタと同程度よく使われる機能がWebコンソールだと思います。</p>

<p>ここには様々なログが出力されます。console.log経由で出力されるもの以外にも、CSSやJavaScriptのエラー、通信の状況などが出力されます。出力するログは画面上部、ツールバー中のボタンをトグルすることで、フィルターできます。</p>

<p>要素の追加、削除、:hoverのような疑似クラスのアクティブ化といったことで起きるページの再秒にかかった時間も出力されます。ツールバーのCSSボタンををクリックして、ログを選択することで再描画時間が表示されます。この再描画がJavaScriptによって発生した場合、発生源のコード行へのリンクも表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/console-reflow.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/console-reflow-300x87.png" alt="画面の再描画が置きたことと、その処理時間が表示される。" width="300" height="87" class="aligncenter size-medium wp-image-6677" srcset="/wp-content/uploads/2014/05/console-reflow-300x87.png 300w, /wp-content/uploads/2014/05/console-reflow-1024x299.png 1024w, /wp-content/uploads/2014/05/console-reflow-207x60.png 207w, /wp-content/uploads/2014/05/console-reflow.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>JavaScriptデバッガ</h2>

<p>JavaScriptデバッガはその名の通り、JavaScriptをデバッグするツールです。デバッガタブをクリックして利用できます。一般のデバッガ同様、ブレークポイントの設定や、ステップ実行、各スコープ内の変数値の確認、ウオッチ式の設定などが可能です。</p>

<p>ブレークポイントは行に対して設定できるほか、DOMイベントに対しても設定できます。以下のようにリスナが割り当てられているイベントの一覧の中から、ブレークさせたいイベントにチェックを入れます。チェックが入ったイベントが発生すると、そのリスナの視点で実行がブレークされます。</p>

<p>ミニファイされたJavaScriptファイルをデバッグする際には、ファイルの整形機能が便利です。画面左下にある大括弧の書かれたペアをクリックすると、ミニファイされたファイルがが読みやすく整形されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/05/debugger-breakpoint-event.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/05/debugger-breakpoint-event-300x85.png" alt="リストの中からブレークポイントを設定するDOMイベントを選択する" width="300" height="85" class="aligncenter size-medium wp-image-6680" srcset="/wp-content/uploads/2014/05/debugger-breakpoint-event-300x85.png 300w, /wp-content/uploads/2014/05/debugger-breakpoint-event-1024x293.png 1024w, /wp-content/uploads/2014/05/debugger-breakpoint-event-207x59.png 207w, /wp-content/uploads/2014/05/debugger-breakpoint-event.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>まとめ</h2>

<p>Firefoxで利用可能な開発ツールは、<a href="http://getfirebug.com/" title="Firebug" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firebug</a>が有名です。こちらもMozillaの製品で、<a href="http://getfirebug.com/wiki/index.php/Firebug_Extensions" title="Firebugのプラグイン" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">豊富なプラグイン</a>が特徴です。特定のライブラリに対する開発を行うなら、Firebugとそのプラグインを利用する方が効率的に行える場合もあります。</p>

<p>これに対し、今回ご紹介した開発ツールは、オーサリングツールという側面も持っている点が大きな特徴です。編集が描画内容にその場で反映されるだけでなく、コード補完機能やシンタックスハイライト、行番号の表示と言ったエディタとして必要とされる機能も備えているため、単なる修正だけでなく、スクラッチからの作成にも耐えるものとなっています。</p>

<p>Firefoxの開発ツールの概要を、駆け足で見てきました。今回ご紹介したもの以外にも様々な機能を持っています。詳細な情報、使い方については<a href="https://developer.mozilla.org/docs/Tools" title="開発ツールのドキュメント" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"> Mozilla Developers Network (MDN) 内の記事</a>をご覧ください。今回の記事をきっかけに、Firefoxを開発ツールの選択肢に入れていただければ（そしてメインの開発ツールにしていただければ！）幸いです。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Mozilla Japan直伝、Firefoxを使いこなす！]]></series:name>
	</item>
	</channel>
</rss>
