--- title: WebAssembly の概要 slug: WebAssembly/Concepts tags: - C - C++ - Emscripten - JavaScript - Web プラットフォーム - WebAssembly - rust translation_of: WebAssembly/Concepts ---
{{WebAssemblySidebar}}

この記事では、 WebAssembly がどのように機能しているか、その目標、解決している問題、ウェブブラウザーのレンダリングエンジン内での動作などの概念について説明します。

WebAssembly とは何か

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

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

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

WebAssembly の目標

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

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

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

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

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

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

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

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

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

WebAssembly のキーコンセプト

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

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 のエコシステムはまだ黎明期の状態にあります。もっと多くのツール群によってこの状況が進展するのは間違いありません。現時点では主に4つの入口があります。

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

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

WASM コードを作成するための多くのオプションのうちの 2 つは、オンラインの Wasm アセンブラまたは Emscripten です。 WASM のオンラインアセンブラには、次のようなものがあります。

これらは、どこから始めるべきかを把握しようとしている人にとっては素晴らしいリソースですが、 Emscripten のツールと最適化には欠けています。

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 のグルーコードを生成します。

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

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

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

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

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

直接 WebAssembly を記述する

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

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

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

WebAssembly をターゲットとした Rust の記述

Rust WebAssembly ワーキンググループの不断の仕事のおかげで、Rust コードを書いて WebAssembly にコンパイルすることも可能です。必要なツールチェーンをインストールし、サンプル Rust プログラムを WebAssembly npm パッケージにコンパイルし、ウェブアプリケーションのサンプルを使用して、 Rust から WebAssembly へのコンパイルの記事を読むことができます。

AssemblyScript の使用

C や Rust を学ぶ必要なく WebAssembly を試してみたいウェブ開発者には、 AssemblyScript が最良の選択肢です。これは小さなバンドルを生成し、 C や Rust と比較するとやや遅い程度です。ドキュメントは https://assemblyscript.org/ でチェックすることができます。

まとめ

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

関連情報