WebAssembly

WebAssemblyは仮想命令セットアーキテクチャあるいはプログラミング言語の一種である。略称はWasm。C・Rustなど様々なプログラミング言語のコンパイルターゲットとしてWasmバイナリは生成され、ウェブブラウザを含む様々な環境内のスタックベース仮想マシンにより実行される。

ネイティブコード相当の高速性・隔離環境でのメモリ安全な実行による安全性・仮想マシンによるハードウェア/プラットフォーム可搬性・ソースプログラミング言語中立性などを特徴とする。この命令セットはバイナリ形式で定義されており、またアセンブリ言語ライクなテキスト形式も定義されている（その意味で低水準プログラミング言語といえる）。

Wasm自体は命令セットアーキテクチャであり、Linuxカーネルが提供するようなシステムコール（例: ファイルI/O）、Webブラウザが提供するようなDOMアクセスなどを提供していない。上記の安全性や可搬性はこの特徴に由来している。それと同時に、WasmエコシステムとしてはシステムコールやDOMアクセスがAPIとして個別に定義されており、Wasmランタイムが実装することでそれらの機能を提供している（例: システムコールを提供するWASI）。シンプルでオープンなISAとランタイムごとのAPIを組み合わせることでWasmエコシステムは高い拡張性を有している。例えばWasmをHTTPプロキシでのフィルタスクリプトとして利用するプロジェクトが存在する。

仕様 
WebAssemblyはポータブルなスタックマシンであり、既存のウェブブラウザで広く用いられているJavaScriptと比べ、構文解析と実行が高速になるよう設計されている。WASM specification はWASMの言語仕様および実行ファイル形式を定義する。

言語 
Wasmは高水準のアセンブリ言語として設計されている。x64等のアセンブリ言語にみられない特徴として以下がある。

 制御命令: if や loop。直接のJUMP命令が無い、安全かつ高水準の制御フローを実現（構造化プログラミング）
 関数: 型・ローカル変数・ボディで定義され、call される関数。コードの組織化を実現
 ローカル変数: 関数スコープの自動変数。get/set /tee 命令でアクセスでき疑似レジスタとして利用可能

値型 
値に定義される型は i32 / i64 / f32 / f64 の4種類である。char/stringは型としてサポートされない。また、高級言語のように関数が構造体型を取り回すようなコードが直接的には記述できない。

入出力 
デフォルトでは外部と隔離されている（サンドボックス）。計算結果を渡したり外部関数を呼び出したりするために、WASMは imports/exports 機能を提供する。対象となるオブジェクトは関数・テーブル・メモリ・グローバル変数の4種類。exports要素に対象のインデックスを登録することで、WASM外からそのオブジェクトへアクセスできる（関数呼び出しやメモリ読み書き）。またimports要素に対象の名前と型を登録することで、WASM外に存在する対象へのアクセスをWASMランタイムが提供する。

フォーマット 
Wasmはバイナリフォーマット（）およびテキストフォーマット（）を定義している。フォーマットの設計方針として Compact / Modular / Efficient / Streamable / Parallelizable / Portable を掲げている。

言語のバイナリ/テキスト表現（例: オペコード）に加え、実行ファイル形式（コンテナフォーマット）を定義する。module が1つの実行ファイルに相当し、マジックナンバー等のメタ情報が冒頭に記述され、関数やexportsなど11種類のセクションが続く。セクションはサイズ情報を持っており、並行処理可能に設計されている。

以下に、C言語のソースコードが、wasmのリニアアセンブリバイトコードとバイナリにそれぞれ変換された例を示す。

内部的には、wasmコンパイラシステムは中間コードを扱うためにS式を使用している。サンプルを以下に示す。

(module
  (memory 256 256)
  (export "memory" memory)
  (type $FUNCSIG$dd (func (param f64) (result f64)))
  (import $exp "global.Math" "exp" (param f64) (result f64))
  (export "doubleExp" $doubleExp)
  (func $doubleExp (param $0 f64) (result f64)
    (f64.mul
      (call_import $exp
        (get_local $0)
      )
      (f64.const 2)
    )
  )
)

機能

ベクトル演算 
WASMは128ビット幅のベクトル型（v128）をもち、ベクトル命令（）すなわちSIMD命令を定義している。WASM SIMDはChromiumでサポートされている。

連携 
Wasmはホスト環境に埋め込まれるサンドボックスであり、import/exportを介したホストとの連携によって意味ある結果が得られる。WasmがシンプルなVMである反面として、Wasm-ホスト間の連携にはいくつかのテクニックが必要となる。また各moduleが1つのサンドボックスとして働くため、Wasmモジュール間の連携にも同様のことが言える。

基本的な問題として、Wasm-ホスト間の型システム不一致解消（マーシャリング）を取り扱うことになる。

文字列 
char/stringは型としてサポートされない。Wasm上で扱うためにはcharをintとして操作し、線形メモリ上にchar配列を構築する形になる。export関数も数値型しか返せないため、stringの表現として線形メモリのオフセットと長さを返し（intなので返せる）これに基づきランタイム側で該当メモリ区間を文字列型として読む、といった工夫が必要となる。あるいはmalloc等の外部アロケータをimportした上で線形メモリの内容を外部メモリへ割り当て、そのアドレス・参照をintでランタイムへ返す必要がある。

ツール 
 Emscripten - 元々asm.js向けであったが、その後、WebAssemblyにも対応した。C言語/C++からWebAssemblyへのコンパイルでは、フロントエンドにclangもしくはそのforkであるfastcomp-clangを、中間層にLLVMもしくはそのforkであるfastcompを、バックエンドにbinaryen (後述)を使用する。なお、LLVMのWebAssembly実装とFastcompのWebAssembly実装は別物である。
 GCC asm.js backend - asm.js及びWebAssemblyに対応している。
 LLVM - WebAssemblyバックエンドを持ち、WebAssemblyバイナリを直接出力できる。また、LLDによるWebAssemblyバイナリのリンクも可能。LLVM 8.0で正式に対応した。

バックエンド 
 Binaryen
 asm2wasm - asm.jsからWebAssemblyテキストへのコンバータ。
 s2wasm - LLVMのWebAssembly用テキストアセンブリ (*.s)からWebAssemblyテキストへのコンバータ。
 mir2wasm - Rust言語の中間レベルIR (MIR)からWebAssemblyテキストへのコンバータ。
 wasm-as - WebAssemblyテキストからWebAssemblyバイナリへのコンバータ。
 WABT
 wat2wasm - WebAssemblyテキストからWebAssemblyバイナリへのコンバータ。
 wasm-link - WebAssemblyバイナリのリンカー

ランタイム 
仮想マシンの命令セットであるWASMはコンピュータの実行ファイルではないため、そのまま機械語として実行はできない。そのためWASMファイルはランタイムを介し解釈・実行される。ランタイムにはインタプリタ/JITコンパイラ/AOTコンパイラがあり用途に合わせて選択される。

ランタイムはウェブブラウザへの組み込み（JavaScript実行環境からの呼び出し）や独立したWASMネイティブランタイム (例: CLIにおける $ wasmtime foo.wasm) として存在する。

かつて存在したランタイムにはCraneliftコンパイラベースのLucetがある。

開発環境 

 WebAssembly Studio - WebベースのWebAssembly向け開発環境。C言語及びRustに対応している。オープンソース。

ライブラリ 

 Qt for WebAssembly - アプリケーションフレームワークのQtをWebAssemblyに移植したもの。2018年4月現在、テクノロジープレビュー。

歴史 
WebAssemblyサポートの初期実装は、既存のとPNaClをベースとしている。

WebAssemblyの最初のアナウンスは2015年6月17日に行われ、2016年3月15日には主要ブラウザ (Firefox, Chromium, Google Chrome, Microsoft Edge) 上でUnityによるAngry Botsというデモが行われた。

最初の目標としてCとC++からのコンパイルをサポートすることを目指し、Rustがバージョン1.14以降で、Goがバージョン1.11以降で、Kotlin/Nativeがバージョン0.4以降でで対応するなど、他のプログラミング言語のサポートも進められた。

2017年3月7日には、WebAssemblyに標準対応した初のブラウザとなるFirefox 52.0がリリースされた。2017年11月、MozillaはSafariとEdgeがWebAssemblyに対応したと発表し、すでに対応しているChromeとFirefoxを含め、主要なブラウザすべてでサポートされることになった。

2019-12-05にはW3C勧告「WebAssembly Core Specification」が策定され、WebAssemblyは正式なウェブ標準に認定された。

ガベージコレクション (GC) の対応を行い、JavaやC#といったGCを持つ言語をサポート対象に加えることが計画されている。

WebAssemblyの開発はMozilla、マイクロソフト、Google、Appleといった主要ブラウザの開発者により行われている。

参考文献 
 V8.dev. WebAssembly compilation pipeline.

脚注

関連項目 
 
 Emscripten

外部リンク
  
 WebAssembly Community Group 
 WebAssembly Design 

アセンブリ言語
ウェブ開発
W3C勧告