MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

WebAssembly のコンセプト

本項では最終的な目標、解決できる問題、そしてどのようにブラウザーのレンダリングエンジン内で動作するかを含みながら WebAssembly がどのように機能するかの概念について説明します。

WebAssembly とは何か ?

WebAssembly はモダンなウェブブラウザで動作して新たな機能と大幅なパフォーマンス向上を提供する新しい種類のコードです。基本的に直接記述ではなく、C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。

この機能はウェブプラットフォームにとって大きな意味を持ちます — ウェブ上で動作するクライアントアプリで従来は実現できなかった、ネイティブ水準の速度で複数の言語で記述されたコードをウェブ上で動作させる方法を提供します。

それ以上に、その利点を享受するために利用者は WebAssembly のコードをどのように作成するのか知る必要さえ有りません。 WebAssembly モジュールはウェブ (あるいは Node.js) アプリにインポートする事ができ、WebAssembly の機能は JavaScript を経由して他の領域から利用できる状態になります。JavaScript 製フレームワークでは大幅なパフォーマンス改善と開発中の新機能をウェブ開発者が容易に利用できるようにするために WebAssembly を用いることができます。

WebAssembly の目標

WebAssembly は W3C WebAssembly Community Group 内で策定されるオープン標準として以下を目標に定めて作成されています:

  • 高速で、高効率であり、ポータブルである事 — WebAssembly のコードは 共通ハードウェア対応環境 を利用して異なるプラットフォーム間でネイティブ水準の速度で実行可能です。
  • 可読性を持ちデバッグ可能である事 — WebAssembly は低水準のアセンブリ言語ですが、人間が意味を理解できる、つまり直接記述、閲覧、デバッグできるフォーマットを持ちません (その仕様は依然策定中です) 。
  • 堅牢である事 — WebAssembly は安全な、サンドボックス化された実行環境上で動作するように設計されています。他のウェブ言語と同様に、ブラウザに対して same-origin および権限ポリシーの確認を要求します。
  • ウェブを破壊しない事 — WebAssembly は他のウェブ技術と共に問題なく利用できて後方互換性を維持するように設計されます。

Note: WebAssembly はまたウェブの領域外の JavaScript 環境での利用も行います (Non-web embeddings を参照)。

WebAssembly はどのようにウェブプラットフォームに適合するのか ?

ウェブプラットフォームは 2 つの領域からなると考える事ができます:

  • ウェブアプリのコードを実行する仮想マシン (VM) 、例としてアプリを動作させる JavaScript コード。
  • ウェブブラウザ / デバイスの機能をコントロールして物事を実現するためにウェブアプリが呼ぶことのできる Web API のセット (DOM、 CSSOM、 WebGL、 IndexedDB、 Web Audio API 等)。

歴史的に、仮想マシンは JavaScript を読み込む事しかできませんでした。 JavaScript が今日のウェブで人々が遭遇する多くの問題を解決する上で十分にパワフルであるため私達にとって仮想マシンはとても有効でした。しかしながら私達は JavaScript をもっと厳しい状況、3D ゲーム、VR に AR、コンピュータビジョン、画像/動画編集等ネイティブの性能が要求されるような多くの領域 (これら以外の利用アイディアに関しては WebAssembly use cases を参照) において用いる際にパフォーマンス上の問題に遭遇するようになっています。

加えて巨大な JavaScript アプリケーションのダウンロード、構造の解析とコンパイルのコストは異常に高いものになりえます。モバイルや他のリソースが限られたプラットフォームではこのようなパフォーマンスのボトルネックの影響をずっと強く受ける事になります。

WebAssembly は JavaScript と異なる言語ですが、その置き換えを意図していません。その代わり、JavaScript の足りない所を補填して併用し、ウェブ開発者に双方の以下のような利益を提供する事を狙いとしています:

  • JavaScript は高水準の言語であり、ウェブアプリケーションを作る上で十分な柔軟性と表現力を持っています。そして多くの利点 — 動的型付け言語である、コンパイルが必須でない、パワフルなフレームワーク、ライブラリやツールを提供する豊富な土壌等を持っています。
  • WebAssembly はネイティブに近いパフォーマンスで動作して、 C++ や Rust のような低水準のメモリ管理を行う言語がウェブ上で動作するようコンパイルされる対象となる、コンパクトなバイナリ形式を持つ低水準なアセンブリに似た言語です ( WebAssembly は将来的にガベージコレクトによるメモリ管理を行う言語をサポートする 高レベルの目標 を持っている事に注意して下さい )。

ブラウザにおいての WebAssembly の登場によって、私達が先述したような仮想マシンはこれから 2 つの種類の言語をロードして実行することになります — JavaScript と WebAssembly です。

必要に応じてこの異なったコードは互いを呼び出し合う事ができます — WebAssembly JavaScript API はエクスポートした WebAssembly のコードを普遍的に呼び出せる JavaScript 関数でラップし、WebAssembly のコードは通常の JavaScript 関数をインポートして同期的に呼び出せます。実際、WebAssembly のコードの基本単位はモジュールと呼ばれ、WebAssembly のモジュールは ES2015 のモジュールと多くの対になる概念を持っています。

WebAssembly のキーコンセプト

ブラウザ上で WebAssembly がどのように動作するかを理解するため必要となるキーコンセプトがいくつか存在します。これらのコンセプトはそれぞれが WebAssembly JavaScript API に一対一で対応しています。

  • Module (モジュール): ブラウザによって実行可能な機械語にコンパイルされた WebAssembly のバイナリに対応します。モジュールはステートレスであるため、Blob のように、明示的に IndexedDB にキャッシュ できたり window やウェブワーカーと ( postMessage() を経由して ) 共有する事ができます。モジュールは ES2015 のモジュールのように import と export の宣言を行います。 
  • Memory (メモリ): WebAssembly の低水準なメモリアクセス命令によって読み込みおよび書き込みが行われるバイト列を一次元の配列として保持している、リサイズ可能な ArrayBuffer です。
  • Table (テーブル): メモリ内に ( 安全性およびポータブル性を維持するため ) バイト列として保持することができなかった ( 関数等に対する ) 参照を保持しているリサイズ可能な型付き配列です。
  • Instance (インスタンス): メモリ、テーブル、インポートされた値を含む実行時に利用される全ての状態と対となるモジュールです。インスタンスは特定の import によって特定のグローバル環境にロードされた ES2015 におけるモジュールのような物です。

JavaScript API はモジュール、メモリ、テーブル及びインスタンスを作る機能を開発者に提供します。 WebAssembly のインスタンスが与えられれば、 JavaScript はその中で export されたオブジェクトを、一般的な JavaScript で渡せる状態にされた関数同様に、同期的に呼び出すことができます。また任意の JavaScript の関数はその関数を WebAssembly のインスタンスに import する事で WebAssembly のコードから同期的に呼び出されるようにする事もできます。

JavaScript は WebAssembly のコードがどのようにダウンロードされ、コンパイルされて実行されるかを完全に制御できるため、 JavaScript 開発者は WebAssembly を単に効果的に高いパフォーマンスを発揮する JavaScript の機能のようにとらえることもできます。

将来的には、WebAssembly モジュールは ( <script type='module'> を利用して ) ES2015 モジュールのようにロード可能 となり、これは JavaScript が WebAssembly モジュールを ES2015 モジュールと同じくらい簡単に取得、コンパイル、インポートできるようになる事を意味します。

WebAssembly をどのようにアプリで用いるか ?

ここまで私達は WebAssembly がウェブプラットフォームに付加する基本的な原則について話しました: つまりコードのバイナリ形式とバイナリコードを読み込み実行する API について。ここからは実際にこれらの原則をどのように活かすのかについて話します。

WebAssembly のエコシステムはまだ黎明期の状態に有ります; もっと多くのツール群によってこの状況が進展するのは間違い有りません。現時点では主に 2 つのエントリーポイントが存在します:

  • Emscripten を用いて C/C++ 製アプリケーションをポーティングする。
  • アセンブリ水準で WebAssembly を記述もしくは直接生成する。

これらの選択肢について考えてみましょう:

C/C++ からのポーティング

Emscripten ツールは C/C++ ソースコードを取得し、それを .wasm モジュール、加えてモジュールを読みだして実行するために必要な JavaScript に "glue(グルー、接着する)" コードとコードの結果を表示するための HTML 文章にコンパイルおよび出力します。

簡潔に言えば、このプロセスは以下のような物になります:

  1. Emscripten は最初に C/C++ を Clang + LLVM — 完成度の高いオープンソースの C/C++ コンパイラ・ツールチェインであり、OSX の XCode の一部として提供される等の利用例が有る、に注入します。
  2. Emscripten が Clang + LLVM によるコンパイル結果を .wasm バイナリに変換します。
  3. それ自体だけでは WebAssembly は現時点で DOM に直接アクセスできません; JavaScript を呼び出して、整数型もしくは浮動小数点型の基本データを渡せるだけです。そのため、ウェブ API にアクセスするためには、 WebAssembly は JavaScript を呼び出す必要が有り、この時点でウェブ API の呼び出しが行われます。そのため Emscripten は結果を得るための HTML と JavaScript のグルーコードを生成します。

Note: 将来的に WebAssembly に直接ウェブ API を呼ばせる事を許容する 計画が有ります。

JavaScript グルーコードは多くの人がそうぞうするほど簡単な構造をしていません。はじめに、 Emscripten は SDL、 OpenGL、 OpenAL および POSIX の一部といった主な C/C++ ライブラリを組み込みます。これらのライブラリ群はウェブ API の観点から組み込まれ、各々が WebAssembly を既存のウェブ API に接続するためにいくつかの JavaScript グルーコードを必要とします。

そのためグルーコードの一部は C/C++ コードによって利用されるそれぞれのライブラリの機能を組み込みます。グルーコードはまた .wasm ファイルを取得、ロード、実行するため先述した WebAssembly JavaScript API を呼び出すロジックも含んでいます。 

生成された HTML 文章は JavaScript グルーコードのファイルを読み込んで <textarea> に標準出力を書き出します。もしアプリケーションが OpenGL を利用している場合、その HTML はまた出力先となる <canvas> 要素を含みます。 Emscripten の出力結果を修正して必要とするウェブアプリに変換するのは非常に簡単です。

Emscripten に関する完全なドキュメントは emscripten.org で参照でき、このツールチェインの組み込みと自身の C/C++ アプリを wasm へとコンパイルするガイドとしては C/C++ を WebAssembly にコンパイルする が参考になります。

直接 WebAssembly を記述する

独自のコンパイラ、ツール、あるいは WebAssembly を実行時に生成する JavaScript のライブラリを作りたいとお考えですか ?

実際のアセンブリ言語同様、WebAssembly バイナリ形式はテキスト表現を持っています— これらは一対一で対応しています。なんらかの WebAssemby テキスト表現バイナリ変換ツール を用いることでテキスト表現を直接記述してバイナリ形式に変換することができます。

この手順に関しては、WebAssembly テキスト表現を wasm 形式に変換する  の項目を参照ください。

まとめ

本項目では WebAssembly が何であるか、どういった利便性が有るか、どのようにしてウェブに適用するかとどのように活用するかについて説明しました。

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: syu_kato, takashi
 最終更新者: syu_kato,