<?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>asm.js &#8211; HTML5Experts.jp</title>
	<atom:link href="/tag/asm-js/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>WebAssemblyの基礎から最新動向まで、@chikoskiに聞いてきた！</title>
		<link>/shumpei-shiraishi/24409/</link>
		<pubDate>Wed, 25 Oct 2017 01:00:17 +0000</pubDate>
		<dc:creator><![CDATA[白石 俊平]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=24409</guid>
		<description><![CDATA[連載： HTML5 Conference 2017特集 (9)こんにちは、編集長の白石です。 この記事は、9月24日に開催されたHTML5 Conference 2017に登壇したエキスパートに、お話されたセッションのト...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/html5-conf2017/" class="series-457" title="HTML5 Conference 2017特集" data-wpel-link="internal">HTML5 Conference 2017特集</a> (9)</div><p>こんにちは、編集長の白石です。</p>

<p>この記事は、9月24日に開催された<a href="http://events.html5j.org/conference/2017/9/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Conference 2017</a>に登壇したエキスパートに、お話されたセッションのトピックを中心に、様々なお話を伺おうというものです。セッションの内容をより深く理解する手助けになるだけでなく、本記事単体でも面白く読んでいただけることを目指しています。</p>

<p>今回お話を伺ったのは、WebAssemblyコミュニティを率いてらっしゃる清水 智公さん（@chikoski）です。清水さんのセッションは「<a href="http://events.html5j.org/conference/2017/9/session/#d5" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">WebAssembly MVPまとめと、今の議論の内容からいくつか</a>」でした。</p>

<p><img src="/wp-content/uploads/2017/10/DSC05255.jpg" alt="" width="640" height="409" class="alignnone size-full wp-image-24599" srcset="/wp-content/uploads/2017/10/DSC05255.jpg 640w, /wp-content/uploads/2017/10/DSC05255-300x192.jpg 300w, /wp-content/uploads/2017/10/DSC05255-207x132.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>※スライド資料は<a href="https://speakerdeck.com/chikoski/20170924-html5conference-wasm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちら</a>で公開されています。</p>

<iframe class="embedly-embed" src="//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fspeakerdeck.com%2Fplayer%2F847ab70cbf364637b574d6ee1d8382ce&#038;url=https%3A%2F%2Fspeakerdeck.com%2Fchikoski%2F20170924-html5conference-wasm&#038;image=https%3A%2F%2Fspeakerd.s3.amazonaws.com%2Fpresentations%2F847ab70cbf364637b574d6ee1d8382ce%2Fslide_0.jpg&#038;key=internal&#038;type=text%2Fhtml&#038;schema=speakerdeck" width="500" height="416" scrolling="no" frameborder="0" allowfullscreen></iframe>

<p><br></p>

<h2>WebAssemblyとは何か？</h2>

<p><b class="speaker siraisi">白石:</b> 今日はよろしくお願いします。まずは自己紹介をお願いできますか？</p>

<p><b class="speaker simizu">清水:</b> WebAssemblyのコミュニティを運営している清水です。<a href="https://twitter.com/ikkou" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">@ikko</a>さんと一緒に、「<a href="https://emsn.connpass.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">emcscripten night !!</a>」というイベントを四半期に一回くらいのペースで開催しています。</p>

<p><b class="speaker siraisi">白石:</b> では早速ですが、<strong>WebAssembly（WASM）とは何なんでしょうか？</strong></p>

<p><b class="speaker simizu">清水:</b> 一言で言うと、<strong>Webブラウザ上で実行できる、ポータブルなバイナリ形式</strong>です。現在、「MVP（Minimul Viable Product: 最小限有用な機能を備えたプロダクト）」の実装が完了し、ほぼすべてのメジャーブラウザで利用できるという状態です。</p>

<p><b class="speaker siraisi">白石:</b> ポータブルというと、ブラウザにも、OSにも、デバイスにも依存しないということですね。</p>

<p><b class="speaker simizu">清水:</b> その通りです。Javaをご存じの方であれば、classファイル形式を思い浮かべていただくと理解は早いと思います。</p>

<p><b class="speaker siraisi">白石:</b> なるほど。なぜそうしたバイナリ形式が必要とされたんでしょうか？</p>

<p><b class="speaker simizu">清水:</b> これまでWebページで動作するプログラミング言語といえば当然JavaScriptだったわけですが、<strong>JavaScriptは遅い</strong>という問題がありました。asm.jsでスピードの面は大分改善されたのですが、今度はサイズが大きくなってしまうという問題も生まれました。それで早く動かせて、サイズもasm.jsよりは小さいものとして、WebAssemblyが生まれたんです。</p>

<p>遅さの原因の一つは、JavaScriptは変数の型が動的だということです。例えばJavaScriptで足し算を行うコードがあるとしたら、いろんな可能性を考慮しなくちゃいけないんですよね。</p>

<p>値が整数かもしれないし、浮動小数点かもしれない。文字列かもしれないし、<code>valueOf()</code>を持つオブジェクトかもしれない。こういう可能性を踏まえると、単なる足し算といえども最適化は容易じゃないわけです。</p>

<p>ですがWebAssemblyの場合は、コンパイル時に変数の型が決まるので、最適化が容易なんです。今では、<strong>ネイティブに比べて2/3くらいの速度</strong>というところまで改善されています。</p>

<p><b class="speaker siraisi">白石:</b> なるほど。サイズが小さくなるという点についてはいかがでしょう。</p>

<p><b class="speaker simizu">清水:</b> JavaScriptは当然テキスト形式ですが、テキストってやはり冗長なんですよね。例えば、とあるゲームのコードを全部JavaScriptに変換したところ、40メガバイトを超えるサイズになってしまったことがあります。</p>

<p>これでは、JavaScriptのソースコードをダウンロードするだけでかなりの時間がかかってしまうし、実行にかかるコストも半端ではありません。</p>

<p>WebAssemblyは、サイズを小さくすることを最初から念頭に置いたバイナリ形式ですので、確実にサイズは縮まります。元のJavaScriptファイルにもよりますが、ミニファイして圧縮した場合に比べても小さくなるのは確実。場合によっては半分以下のサイズになることもあります。</p>

<p><b class="speaker siraisi">白石:</b> それほど素晴らしいのであれば、将来的にはJavaScriptを置き換えていくような存在になるのでしょうか？</p>

<p><b class="speaker simizu">清水:</b> いえ、WASMはJavaScriptの置き換えは目指しておらず、あくまで補完する存在という位置付けです。例えば、WASMはDOMに直接アクセスすることができませんからね。</p>

<h2>WASMへの対応状況</h2>

<p><b class="speaker siraisi">白石:</b> では改めて、ブラウザのWASMへの対応状況を教えていただけますか？</p>

<p><b class="speaker simizu">清水:</b> 先ほども申し上げたとおり、ほとんどのメジャーブラウザで使えます（参考: <a href="http://caniuse.com/#feat=wasm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Can I Use</a>）。Safariが11から対応するようになったのは大きいですね。iOSでも使えるようになったということなので。
Edgeも先日のCreator’s updateでデフォルトでWebAssemblyを利用できるようになりました。また、Node.jsでもWebAssemblyは動作します。</p>

<p><b class="speaker siraisi">白石:</b> Nodeでも動くんですか！知りませんでした。WASMにコンパイル可能な言語には、どのようなものがありますか？</p>

<p><b class="speaker simizu">清水:</b> 様々なコンパイラで利用されている、<a href="https://ja.wikipedia.org/wiki/LLVM" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">LLVM</a>という中間言語があるんですが、LLVMに変換される言語だったらだいたい大丈夫です。<a href="https://github.com/kripken/emscripten" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Emscripten</a>というツールを使うと、LLVMからWASMに変換できるのです。</p>

<p>LLVMにコンパイルできる言語というと、C/C++/Objective-Cなどが挙げられます。また、<a href="https://www.rust-lang.org/ja-JP/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Rust</a>もWebAssemblyに対応しています。</p>

<p>あとUnity限定になってしまうのですが、C#にも対応しています。他には<a href="https://github.com/AssemblyScript/assemblyscript" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">AssemblyScript</a>といって、WebAssemblyを出力できるTypeScriptのサブセット言語も存在します。</p>

<p><b class="speaker siraisi">白石:</b> C#やTypeScriptもあるんですね！WebAssemblyにはガベージコレクタがないと聞いていたので、それらの言語が使えるというのは驚きです。</p>

<p>ちなみに、WASMを出力できる言語や動作する環境がたくさんあるのはわかったのですが、実際どれくらい実用的なんでしょうか？</p>

<p><b class="speaker simizu">清水:</b> 今は、<strong>ざっくり言ってC言語のコードをコンパイルして動かす能力は備えている</strong>というところです。
C++への対応は完全じゃありません。C++の例外をまだうまく扱えないんですよね。</p>

<p><b class="speaker siraisi">白石:</b> Cと言えば、メモリを直接操作するようなコードを直接書けると思うのですが、それがWebAssembly上だとどのように動作するのでしょうか？</p>

<p><b class="speaker simizu">清水:</b> WebAssemblyのコードには専用のメモリ空間が割り当てられるんです。C言語におけるメモリ操作などは、そのメモリ空間に対して行われます。そのメモリ空間は、JavaScriptコードからも<code>ArrayBuffer</code>オブジェクトとして参照できます。</p>

<p>ちなみに、WebAssemblyの仕様上は64ビットのメモリ空間を扱えるのですが、現在の実装上では32ビットに制限されていますね。</p>

<h2>WASMを使う</h2>

<p><b class="speaker siraisi">白石:</b> WASMを使うコードはどういうふうになりますか？</p>

<p><b class="speaker simizu">清水:</b> まず、WASMのバイナリが必要です。拡張子は<code>.wasm</code>です。そのファイルを<code>fetch()</code>でも<code>XMLHttpRequest</code>でも何でもいいので読み込んで、バイナリコードを<code>ArrayBuffer</code>化し、<code>WebAssembly.instanciate()</code>というメソッドに渡します。</p>

<p>すると、WebAssemblyコードの実行結果が<code>Promise</code>の戻り値として返ってくるので、そこにエクスポートされている関数をJavaScript側から呼び出すことが可能です。</p>

<p></p><pre class="crayon-plain-tag">// MDNのサンプルを引用
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate

// WASMファイルを読み込み
fetch('sample.wasm').then(response =&gt;
  // ArrayBuffer化
  response.arrayBuffer()
).then(bytes =&gt;
  // インスタンスを生成
  WebAssembly.instantiate(bytes)
).then(result =&gt;
  // 生成されたインスタンスのエキスポートされた関数を呼び出し
  result.instance.exports.exported_func()
);</pre><p></p>

<p><b class="speaker siraisi">白石:</b> なるほど、使うのはそれほど難しくなさそうですね。JavaScriptからシームレスに関数の呼び出しを行えるのが素晴らしい。</p>

<p><b class="speaker simizu">清水:</b> はい、それにWASMのコード内から、外部JavaScriptのコードを呼び出すことも簡単にできます。<code>WebAssembly.instantiate()</code>の第二引数で、WASMコードがインポートするメンバーを指定できるんです。</p>

<p></p><pre class="crayon-plain-tag">// MDNのサンプルを引用
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate

// WASMがインポートして使用するオブジェクト
var importObject = {
  imports: {
    imported_func: function(arg) {
      console.log(arg);
    }
  }
};
fetch('simple.wasm').then(response =&gt;
  response.arrayBuffer()
).then(bytes =&gt;
  // インポートするオブジェクトを指定
  WebAssembly.instantiate(bytes, importObject)
).then(result =&gt;
  result.instance.exports.exported_func()
);</pre><p></p>

<p><b class="speaker siraisi">白石:</b> なるほど、ダイナミックリンクが可能なんですね。WASMがJavaScriptをどう補完するのか、よくわかりました。</p>

<h2>WASMはどう使われていくか</h2>

<p><b class="speaker siraisi">白石:</b> WASMが登場したことで、具体的に何が変わっていくと思いますか？</p>

<p><b class="speaker simizu">清水:</b> まずはやはり、C/C++で書かれたコードをWASMに変換して使うのが一番最初に思いつくユースケースです。
コンシューマー向けのサービスでいうと、やはりゲーム系がすぐに思いつきますね。</p>

<p>例えば新たなゲームタイトルをスマホ向けにネイティブで開発しつつ、WASMでコンパイルしてWeb版も同時に開発するということができます。
UnityはWebAssemblyに対応しているので、そういう開発を行うのは比較的簡単です。</p>

<p><b class="speaker siraisi">白石:</b> なるほど、スマホ版だけじゃなくてWeb版も同時に開発して公開できれば、ユーザーへのリーチが拡大しそうですね。</p>

<p><b class="speaker simizu">清水:</b> 実際、とあるベンダーさんが、Android用のゲームをWebブラウザでも動作するようにしたところ、ユーザー数はかなり増えたと聞いています。</p>

<p><b class="speaker siraisi">白石:</b> では、<strong>まずはネイティブとWebのクロスプラットフォーム開発でWASMは活躍しそう</strong>だと。
<strong>他にはC言語で書かれた資産とかもWeb上で使えそう</strong>ですよね。例えばgzipのライブラリとか。</p>

<p><b class="speaker simizu">清水:</b> そう、圧縮や暗号系、画像処理などの、Cで書かれたライブラリをWeb上に移植するのにも向いていますね。
CPUに依存する処理を高速化するのには、すごく向いています。</p>

<p>Cで書かれたコードの移植といえば、<a href="https://github.com/vvanders/wasm_lua" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">lua</a>もWASMにコンパイルできたそうです。</p>

<p><b class="speaker siraisi">白石:</b> おお、言語処理系まで！そうか、よく考えたら、現在のWASMにガベージコレクタがなくとも、ガベージコレクタを備えた処理系ごとコンパイルしちゃえばいいんですね。</p>

<h2>WASMのこれから</h2>

<p><b class="speaker simizu">清水:</b> はい、ちょうどガベージコレクタの話が出たので、WASMのこれからという話をしたいと思います。WASMの次のターゲットとして、<a href="https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ガベージコレクタが提案されています</a>。</p>

<p>こちらはおそらく、「ガベージコレクタを使いたい場合は使える」という設計になると予想されています。</p>

<p><b class="speaker siraisi">白石:</b> ガベージコレクタが使えるようになったら、WASMをターゲットにした言語処理系とかが作りやすくなりそうですね。WASMで提案されている仕様は他にもありますか？</p>

<p><b class="speaker simizu">清水:</b> まず、<a href="https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">スレッドを使えるようにする</a>という提案があります。
やはり、pthread (POSIXスレッド: C言語で使用できるマルチスレッドAPI)を使いたいという要望が多いんですね。
複数のWeb Workers（Web環境でマルチスレッディングが可能なAPI）で共有できる Shared ArrayBuffer は既に利用可能ですが、複数のスレッドを待ち合わせる<code>wait</code>や<code>wake</code>と言った命令も使えるようにすることを見据えています。</p>

<p>他には、先ほども申し上げたように<a href="https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">例外</a>を扱えるようにして、C++コードもWASMに正しくコンパイルできるようにすること。WASMのモジュールとECMA Scriptモジュールの整合性を取る…と言った提案も行われています。</p>

<p><b class="speaker siraisi">白石:</b> WASMの未来、楽しみですねー。最後にお聞きしたいのですが、現時点でWASMを試すのにおすすめの言語はありますか？C/C++で書くのはなかなかしんどいなあ、と…</p>

<p><b class="speaker simizu">清水:</b> HTML5 Experts.jpの読者に向けてという話であれば、TypeScript（のサブセット）をWASMにコンパイルできる、<a href="https://github.com/AssemblyScript/assemblyscript" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">AssemblyScript</a>を使うのはおすすめです。Web技術者が軽く試してみるという用途には最適だと思います。</p>

<p><b class="speaker siraisi">白石:</b> 本日は、WebAssemblyについて基礎から最新情報まで教えていただき、ありがとうございました。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2017特集]]></series:name>
	</item>
		<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>「進化を続ける JavaScript ～次世代言語のステキな機能と高速化の行方～」HTML5 Conference 2013 セッションレポート</title>
		<link>/yosssi/3572/</link>
		<pubDate>Fri, 13 Dec 2013 01:00:13 +0000</pubDate>
		<dc:creator><![CDATA[吉田 啓二]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ECMAScript]]></category>
		<category><![CDATA[ECMAScript 6th]]></category>
		<category><![CDATA[HTML5 Conference 2013]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[asm.js]]></category>

		<guid isPermaLink="false">/?p=3572</guid>
		<description><![CDATA[連載： HTML5 Conference 2013レポート (2)2013年11月30日（土）に開催された「HTML5 Conference 2013」の、Mozilla Japan浅井智也さんによるセッション「進化を続...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/html5-conference-2013-2/" class="series-160" title="HTML5 Conference 2013レポート" data-wpel-link="internal">HTML5 Conference 2013レポート</a> (2)</div><p>2013年11月30日（土）に開催された「<a href="http://events.html5j.org/conference/2013/11/" title="HTML5 Conference 2013" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Conference 2013</a>」の、Mozilla Japan浅井智也さんによるセッション「進化を続ける JavaScript ～次世代言語のステキな機能と高速化の行方～」のセッション内容をご紹介します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/12/html5conference-report-javascript-01.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/12/html5conference-report-javascript-01-1024x569.png" alt="html5conference-report-javascript-01" width="1024" height="569" class="aligncenter size-large wp-image-3574" srcset="/wp-content/uploads/2013/12/html5conference-report-javascript-01-1024x569.png 1024w, /wp-content/uploads/2013/12/html5conference-report-javascript-01-300x166.png 300w, /wp-content/uploads/2013/12/html5conference-report-javascript-01-207x114.png 207w, /wp-content/uploads/2013/12/html5conference-report-javascript-01.png 640w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>

<h2>JavaScriptの課題と改良への動き</h2>

<p>現在のJavaScriptには、次のような課題があります。</p>

<ul>
<li>高速化がなかなかできない</li>
<li>クラス、モジュールがない</li>
<li>プロトタイプベースであるため、普段Javaなどでクラスを使っている人にとって、メソッド定義や継承がわかりにくい</li>
<li>メソッドとして呼び出したときはthisがそのメソッドのオブジェクトになるが、間違って関数として呼び出すとthisがwindowオブジェクトになるなど、thisの挙動を捉えるのが難しい</li>
<li>argumentsなど、ArrayのようでArrayでなくついarguments.slice()とかしてエラー原因になる、紛らわしいオブジェクトがある</li>
<li>コールバック地獄</li>
<li>実行時エラーが多く、コンパイルエラーが少ないので、デバッグが非常に大変である</li>
</ul>

<p>JavaScriptの歴史について詳しくは<a href="http://www.slideshare.net/dynamis/javascriptnext-returns" title="http://www.slideshare.net/dynamis/javascriptnext-returns" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">過去の講演資料</a>をご覧ください。簡単に言えば次の資料の通りです。次期ECMAScript 6thでは大きく改定されるため、この改定内容はぜひ知っておく必要があります。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/12/javascript2013-131130030521-phpapp01-page13.jpg" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/12/javascript2013-131130030521-phpapp01-page13.jpg" alt="javascript2013-131130030521-phpapp01-page13" width="520" height="390" class="aligncenter size-full wp-image-3578" style="border: 1px solid #000000" /></a></p>

<h2>ECMAScript 6thの概要</h2>

<h3>目標</h3>

<p>ECMAScript 6thの目標は、より開発・テストを行いやすくし、相互運用性を確保し、静的検証（コンパイルエラーの検出）を行える構文・言語仕様を提供することにあります。</p>

<h3>実装・対応状況</h3>

<p>FirefoxのSpiderMonkeyの実装範囲が比較的広く、V8がそれに続く状況になっています。機能によってはV8の方が先に入っていたり、上手く実装されているものもあります。IEは非常に安定した、広く使われている仕様が実装されており、加えて、グローバリゼーション、国際化といったビジネス系の仕様が積極的に提案、実装されています。TypeScriptは、対応範囲がクラスなどに絞られている印象があるのですが、比較的綺麗なコードが生成されます。その他にも、letやconstといったブロックスコープだけを使いたいのでしたらdefs.jsを、あるいはModuleのimport/export機能だけを使いたい場合はes6-module-loaderといったコンパイラも使うことができます。</p>

<h2>Syntax Sugar</h2>

<h3>分割代入 (Destructuring)</h3>

<p>これまでのJavaScriptでは代入文の左辺に変数を一つしか指定できませんでしたが、ECMAScript 6thでは左辺に配列やオブジェクトを指定することができるようになります。これにより、例えば、関数から配列やオブジェクトなどで複数の返り値を受け取り、それをそのまま変数に格納するといった処理を記述できるようになります。JSONから特定のデータを抜き出す、といったことを行うこともできます。</p>

<p></p><pre class="crayon-plain-tag">// 配列で受け取るサンプル: // 値の入れ替え
[a, b] = [b, a];

// 関数から複数の値を返して一気に変数に代入
var [c,d] = (function f() { return [1,2]; })(); // -&gt; c=1, d=2

// 一部省略や入れ子も可能
var [e,,[x,y]] = (function f(){
  return [3,4,[10,20]]
})();

// オブジェクトで受け取るサンプル
var fx={ name:"Firefox", vendor:"Mozilla", ver:26 };
var ch={ name:"Chrome", vendor:"Google", ver:31 };
var browsers={ firefox: fx, chrome: ch }

// 欲しいプロパティだけ一括代入
var { name: n, ver: v } = fx;
// -&gt; n="Firefox", v=26

// 関数の引数から必要なプロパティだけ受け取る
(function ({ vendor: ven }) {
  console.log(ven);
})(fx); // -&gt; "Mozilla"</pre><p></p>

<h3>default &amp; rest parameter</h3>

<p>引数のデフォルト値を設定できたり（default parameter）、関数の残りの引数を配列で受け取ったり（rest parameter）することができます。</p>

<p></p><pre class="crayon-plain-tag">e = document.body; // 何か適当な要素
function setBackgroundColor(element, color='orange') {
  element.style.backgroundColor = color;
}
setBackgroundColor(e); // オレンジに
setBackgroundColor(e, 'blue'); // 青に
setBackgroundColor(e, undefined); // オレンジに

// デフォルト値は呼び出し毎に生成される
// 同一オブジェクトが渡される Python などとは違う
function getObject(o={}) { return o; }
getObject() == getObject() // -&gt; false</pre><p></p>

<p></p><pre class="crayon-plain-tag">￼function f(a, b, ...args) { return args; }
f("IE", "Chrome"); // -&gt; []
f("IE", "Chrome", "Firefox"); // -&gt; ["Firefox"] !

// rest arguments は Array のメソッドが使える
// [].slice.call(arguments) ハックとか不要に
function sortRestArgs(...theArgs) {
  var sortedArgs = theArgs.sort();
  return sortedArgs;
}</pre><p></p>

<h3>配列の内包表記 (Comprehensions)</h3>

<p>for&#8230;ofなどを使って、直接、配列のリテラルを生成することができます。</p>

<p></p><pre class="crayon-plain-tag">// 配列のフィルタとマップ
[for (x of [1,-4,5,3,-7]) if (x &gt; 0) x] // -&gt; [1, 5, 3]
// ES5 なら次のように書く
// [1,-4,5,3,-7].filter(function(x) { return x &gt; 0 });
[for (x of [2,4,6]) x*x] // -&gt; [4, 16, 36]
// ES5 なら次のように書く:
// [2,4,6].map(function (x) { return x*x });

// 配列のデカルト積やラベル生成もシンプルに
[for (i of [0,2,4]) for (j of [5,3]) i*j]
// -&gt; [0, 0, 10, 6, 20, 12]
[for (x of 'abc'.split(''))
 for (y of '123'.split('')) (x+y)];
// -&gt; ["a1","a2","a3","b1","b2","b3","c1","c2","c3"]</pre><p></p>

<h2>Modularity</h2>

<h3>ブロックスコープ (let, const)</h3>

<p>今までのJavaScriptにはブロックスコープがなく、グローバルスコープと関数スコープしかありませんでした。変数をブロックスコープに納めるために、今まではわざわざ関数を作らなければなりませんでしたが、ECMAScript 6thでは、let, constを指定するだけでブロックスコープ変数を作成することができます。</p>

<p></p><pre class="crayon-plain-tag">{
  // let 定義: ブロックスコープ
  let a = 1, b = 10;
  // let 式・文: let (...) に続く式・文中だけで有効
  let (a = 100, c = 300) console.log(a); // -&gt; 100
  // for 文などでの let
  for (let a=0; a&lt;3; a++) {
    console.log(a+b); // -&gt; 10, 11, 12
  }
  console.log(a); // -&gt; 1
}
console.log(a); // × ReferenceError: a is not defined</pre><p></p>

<p></p><pre class="crayon-plain-tag">// 不変定数を定義
const browser = "Firefox";

// 再定義は TypeError となる
const browser = "Internet Explorer";
// TypeError: redeclaration of const browser !

// 定数への代入は単に無視される
browser = "Chrome";
console.log(browser); // -&gt; "Firefox"</pre><p></p>

<h3>Class</h3>

<p>待望のClassが使えるようになります。他のオブジェクト指向の言語と同じような形式でClassを記述することができます。constructorメソッドが初期化時の処理として使われます。</p>

<p></p><pre class="crayon-plain-tag">// クラスベース OOP でよく見る感じ
class Animal {
  constructor(name) {
    this.name = name;
    this.hungry = true;
  }
  eat() {
    this.hungry = false;
  }
  run() {
    this.hungry = true;
  }
}

// 派生クラスの定義がシンプル
class LesserPanda extends Animal {
  constructor(name, tail) {
    super(name);
    this.tail = tail;
  }
}</pre><p></p>

<h3>Module</h3>

<p>今まで、モジュールをインポート・エクスポートする様々なライブラリが作られてきましたが、この機能が公式のものとして提供されることになりました。</p>

<p></p><pre class="crayon-plain-tag">module 'math' {
  export function sum(x, y) {
    return x + y;
  }
  export var hbar = 1.054571726e-34; // ディラック定数
}</pre><p></p>

<p></p><pre class="crayon-plain-tag">import {sum, hbar} from 'math';
alert("2ħ = " + sum(hbar, hbar));

// オブジェクトのプロパティに読み込み
module Math from 'math';
alert("2ħ = " + Math.sum(Math.hbar, Math.hbar));</pre><p></p>

<h2>Readable Code</h2>

<h3>Arrow Function</h3>

<p>今まで、コールバックとして関数を渡す際に「function(&#8230;){&#8230;}」と記述する必要があり、ソースコードが冗長で見にくくなっていましたが、Arrow Functionを使うことでこの関数をシンプルに記載できるようになります。</p>

<p></p><pre class="crayon-plain-tag">// return するだけのコールバックがシンプルに
[1,2,3].map(x =&gt; x * x);
// ES5 ではこう書く必要があった:
// [1,2,3].map(function (x) { return x * x; });

// n! (nの階乗) を求める関数もシンプルに
var factorial=((f=n=&gt;n&gt;1 ?n*f(n-1):1)=&gt;(f))();
factorial(10); // 3628800</pre><p></p>

<p>Arrow Functionには、簡潔に書けるということに加えて、もう一つ良いことがあります。それは、thisが保持・バインドされるということです。今まで、コールバック関数内で呼び出し元のオブジェクトを参照しようとすると、thisがwindowオブジェクトを参照するようになるため、コールバック関数の前で「self = this」などと記載し、この場合はコールバック関数内で「self」を参照しなければなりませんでした。Arrow Functionですと、Arrow Function内のthisが、その外側の関数のthisを参照し続けるという特性があり、このような記載が不要となります。</p>

<h3>Generator</h3>

<p>nextメソッドを持ち、繰り返し処理が実行される際にnextメソッドが呼ばれる特殊なオブジェクトをイテレータ(iterator)と呼びます。イテレータを簡単に生成できるジェネレータ関数によって生成されたイテレータをジェネレータ(generator)と呼びます。ジェネレータ関数では、yieldというキーワードがreturnの代わりに使われており、yieldが実行されるとその引数が返却されて関数の処理が一時停止します。そして、再度関数が実行されるとyieldの次の行から処理が再開し、またyieldが実行されると引数を返却して処理が一時停止する、という処理の流れになります。ジェネレータ関数を使うことで、関数の再起呼び出しを行うことなく、何かしらの繰り返しの処理を行うことができます。</p>

<p></p><pre class="crayon-plain-tag">// ジェネレータ関数 (ジェネレータのコンストラクタ)
function* fibonacci() {
  let [prev, curr] = [0, 1];
  for (;;) {
    [prev, curr] = [curr, prev + curr];
    yield curr; // 値を返して一時停止
  }
}
for (n of fibonacci()) {
  if (n &gt; 20)
    break;
  console.log(n); // 順に 1, 2, 3, 5, 8, 13
}</pre><p></p>

<p>先ほどのfor&#8230;ofの中でジェネレータ関数を使う方法以外にも、毎回明示的にイテレートする方法があります。こちらがイテレータの本来の使い方なのですが、例えば、カウンタを作成する場合、毎回一時停止して内部で保持している値をインクリメントするジェネレータ関数を定義すると、nextメソッドを呼ぶたびにインクリメントされた値を取得する処理を実装することができます。</p>

<p></p><pre class="crayon-plain-tag">function* counterGenerator() {
  let c = 0;
  for (;;) {
    yield c++; // 値を返して一時停止
  }
}
// ジェネレータを生成
let counter = counterGenerator();
// next() メソッドで {value, done} を得る
counter.next(); // -&gt; {value: 0, done: false}
counter.next(); // -&gt; {value: 1, done: false}
counter.next().value; // -&gt; 2
counter.next().value; // -&gt; 3</pre><p></p>

<h3>Promise</h3>

<p>Promiseを使うことで、今までよりもコールバックを非常に簡潔に書けるようになります。また、catchなどの構文も今まで以上に書きやすくなります。Promiseを生成するときに引数として関数を渡し、そこでresolve関数とreject関数を指定します。このresolve関数が呼ばれたときにこのPromiseインスタンスが解決し、このインスタンスのthenメソッドが実行されます。</p>

<p></p><pre class="crayon-plain-tag">let p = new Promise(function (resolve, reject) {
  // 3 秒後に resolve 呼んでプロミスが解決する
  setTimeout(resolve, 3000);
});

// 解決した (resolve が呼ばれた) ときに実行:
p.then(function () {
  alert('3 秒たったよ!');
}).then(function () {
  // 解決済みなので即ここも実行される
  alert('既に 3 秒過ぎてるよ!');
});</pre><p></p>

<p></p><pre class="crayon-plain-tag">p = new Promise(function (resolve, reject) {
  dream(); // 未定義の関数を呼ぶ (エラー発生)
});

// エラー発生時は then をスキップして catch へ
p.then(function (message) {
  // p は解決しないのでこのブロックは実行されない
  alert(message);
}).catch(function (error) {
  // p でエラーが発生するのでこのブロックを実行
  alert(error);
  // -&gt; ReferenceError: dream is not defined
});</pre><p></p>

<h2>New Type &amp; API</h2>

<h3>Collections</h3>

<p>Set型、Map型が追加されます。Setを使うことで、集合に対して要素を追加したり参照したりすることができます。Mapは、キーとそれに対応する値を保持できるものです。配列やオブジェクトではキーとして文字列しか設定できませんでしたが、Mapではキーとしてオブジェクトを設定することができます。</p>

<p></p><pre class="crayon-plain-tag">var set = new Set();
// 集合に追加・確認・削除
set.add("Firefox");
set.add("Thunderbird");
set.add(+0);
set.add(NaN);
set.has("Firefox"); // -&gt; true
set.has("Sunbird"); // -&gt; false
set.delete("Firefox");
set.has("Firefox"); // -&gt; false
// -0 と +0 は区別される, NaN は区別されない
set.has(-0); // -&gt; false
set.has(NaN); // -&gt; true</pre><p></p>

<p></p><pre class="crayon-plain-tag">var map = new Map();
var str = "Mozilla", obj = {}, func = function(){};
// Map に値を格納
map.set(str, "Firefox");
map.set(obj, "Thunderbird");
map.set(func, "Japan");
// キーに対応する値を取得
map.get(str); // -&gt; "Firefox"
map.get(obj); // -&gt; "Thunderbird"
map.get(func); // -&gt; "Japan"
// 設定したキーと引数の比較は == ではないので注意
map.get("Mozilla"); // -&gt; "Firefox"
map.get({}); // -&gt; undefined
map.get(function(){}) // -&gt; undefined</pre><p></p>

<p>ここまで次世代言語仕様の一部をご紹介してきましたが、このようにJavaScriptは構文や機能面でも大きな進化を遂げ、落とし穴が少なくシンプルな記法で書ける言語に進化するのです。<br>
そして一方、広く使われる言語は書きやすいだけでなく高速でなければなりませんが、ここからは速度面の進化についてご紹介します。</p>

<h2>Slow Parts &amp; Fast Parts</h2>

<p>JavaScriptが遅い原因として、JavaScriptが動的型付け言語であることや、JavaScriptにクラスと配列が存在しないことなどがありますが、これらの原因を回避して、JavaScriptエンジンが最適化しやすいコードだけを書くようにすることで、処理を高速化させることができます。例えば、型固定で変数を定義することや、一度定義したオブジェクトのプロパティの追加・削除を行わない、といったことなどに気をつければ、処理を高速化させることができます。このように、JavaScriptエンジンが最適化しやすく、高速化を図れるコードを、私の中で「JavaScript Fast Parts」と呼んでいます。</p>

<h3>Typed Array</h3>

<p>Fast Partsの代表的なものとして、Typed Arrayがあります。これを使うことで、今までJavaScriptではできなかった静的型付け・型の固定を行うことができます。</p>

<p></p><pre class="crayon-plain-tag">// 16 バイト長のバッファを確保
var buffer = new ArrayBuffer(16);
// 32bit 整数 x 4 として読み出すビューを定義
var int32View = new Int32Array(buffer);
// 32bit 整数として 0, 2, 4, 6 を格納
for (var i=0; i&lt;int32View.length; i+ +) { int32View[i]=i*2; }
// 16bit 整数 x 8 として同じバッファを読み出すビュー
var int16View = new Int16Array(buffer); // 実際に読み出してみる
for (var i=0; i&lt;int16View.length; i++) {
	console.log(int16View[i]);
}
// -&gt; 0, 0, 2, 0, 4, 0, 6, 0</pre><p></p>

<h2>asm.js</h2>

<p>以上のような高速化できる方法だけを使ってコードを書く、ということをあらかじめルールとして定めてしまい、JavaScriptエンジン側も最初から最適化された状態でコンパイルして高速に実行するようにしよう、という発想に基づいた高速化方法を、Mozillaがasm.jsとして提案しています。コードを自動生成するための様々なツールが存在していますが、これらは全て、JavaScriptエンジンが速く実行できるコードを生成しようとしています。このように、既存のエンジンにおける高速化のノウハウがある程度溜まっているため、それらのノウハウを結晶させたFast Partsを使って高速化を実現させるということが、asm.jsの発想です。</p>

<p>asm.jsの目的は、WebをNativeと同様の速度にすることです。Native同様の速度にするために、新しいコンパイルの方法を導入したりするわけではありません。現在のJavaScriptエンジンでも、最適化できるコードに関しては、既に型固定の高速なコードが生成されるようになっています。その際に、コード生成のためのオーバーヘッドや型変換時のチェックなどがあり、これらがなければNative並みの速度で実行されるようになりつつあります。このエンジンをそのまま利用して、今まで「このコードを最適化して良いか否か」をヒューリスティックに判別していたところを、asm.jsを利用すると、決め打ちで最適化できるようなります。</p>

<p>既存のJavaScriptエンジンでも、よく使われるコードを見つけて、それらを最適化することが幅広く行われています。しかし、簡単なコードは最適化できても、巨大なコードは最適化できない場合が多く、C言語よりも10倍、20倍遅い場合もあります。asm.jsを利用し、常に最適化するようにした場合は、asm.js導入直後の時点でもC言語の2倍の速度で済むレベルまで高速化されました。asm.jsでの高速化は、現在も改良が進められています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/12/html5conference-report-javascript-02.jpg" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/12/html5conference-report-javascript-02.jpg" alt="html5conference-report-javascript-02" width="520" height="390" class="aligncenter size-full wp-image-3615" style="border: 1px solid #000000" /></a></p>

<h2>結論：Always bet on JavaScript!</h2>

<p>Webは非常に互換性を重視しており、既存のものを動作させ続けながら、機能を追加したり速度を改善したりする必要があります。本日ご説明しました通り、JavaScriptでは、必要な機能の追加や高速化が順次行われているため、JavaScriptはこれまで同様に生き続け、皆さんが勉強する価値のある言語になっていると思っており、これからもJavaScriptを愛して頂ければ嬉しいです。</p>


<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe src="http://www.slideshare.net/slideshow/embed_code/28756192" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" 0="allowfullscreen" class="iframe-class"></iframe>


<div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/dynamis/ecmascript-2013" title="JavaScript (ECMAScript) 2013" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">JavaScript (ECMAScript) 2013</a> </strong> from <strong><a href="http://www.slideshare.net/dynamis" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">dynamis .</a></strong> </div>

<p><br>

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/22MgGmhcmPs" frameborder="0" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>
</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2013レポート]]></series:name>
	</item>
	</channel>
</rss>
