WebAssembly

WebAssembly (Wasm)とは



WebAssembly(Wasm)は、実行可能なコードを表現するためのポータブルなバイナリ形式であり、対応するテキスト形式も定義しています。Wasmは、プログラムとホスト環境間の相互作用を円滑にするためのソフトウェアインターフェースを提供し、当初はウェブブラウザ上での高パフォーマンスなアプリケーションの実現を目的としていました。

しかし、Wasmはウェブ環境に特有の機能に依存しないため、他の環境でも同様に利用できます。オープン標準として開発されており、あらゆるオペレーティングシステムであらゆるプログラミング言語をサポートすることを目指しています。事実、主要なプログラミング言語の多くが、何らかの形でWasmに対応しています。

Wasmは、仮想の命令セットアーキテクチャ、またはプログラミング言語の一種と見なすことができます。多くの場合、C/C++やRustのような言語のコンパイル先としてWasmバイナリが生成され、ウェブブラウザやその他のソフトウェア環境でスタックマシンによって実行されます。ネイティブコードに近い高速性、隔離された環境でのメモリ安全な実行によるセキュリティ、仮想マシンによる可搬性やソースプログラミング言語からの独立性などが特徴です。

Wasmは2015年に発表され、2017年3月に最初のバージョンがリリースされました。2019年12月5日にW3C勧告となり、2021年にはACM SIGPLANのプログラミング言語ソフトウェア賞を受賞しています。技術標準はWorld Wide Web Consortium (W3C)によって管理され、Bytecode Allianceという非営利団体も開発に貢献しています。

歴史



WebAssemblyという名前は、1950年代にまで遡る「アセンブリ言語」の概念を想起させます。これは、アセンブリのようなプログラミングを、ウェブのクライアントサイド(ユーザーのウェブブラウザを通じてユーザーのコンピュータ上で実行される環境)にもたらすことを意味しています。ただし、Wasmは真のアセンブリ言語よりもはるかにハードウェアに依存しない必要があります。

Wasmの最初の発表は2015年6月17日に行われました。2016年3月15日に公開された最初のデモでは、主要なブラウザ(Firefox、ChromiumGoogle Chrome、Microsoft Edge)上でUnityのAngry Botsが動作しました。Wasmの前身となった技術には、Mozillaのasm.jsとGoogle Native Clientがあります。初期の実装はasm.jsの機能セットに基づいて行われました。asm.jsはすでにネイティブに近いコード実行速度を提供しており、Wasmをサポートしていない環境や、セキュリティ上の理由でWasmが無効化されている環境での実用的な代替手段として利用されていました。

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

2017年3月には、MVP(Minimum Viable Product)の設計が完了し、Wasmを標準でサポートした最初のブラウザであるFirefox 52.0がリリースされました。同年11月には、Microsoft EdgeがWasmに対応し、主要なブラウザすべてでサポートされるようになりました。2018年2月には、WebAssembly Working Groupが、3つのワーキングドラフト「Core Specification」「JavaScript Interface」「Web API」を公開しました。

2019年6月には、Chrome 75でWebAssemblyスレッドが有効化され、同年12月5日には、W3C勧告「WebAssembly Core Specification」が策定され、Wasmは正式なウェブ標準として認定されました。

2022年8月からは、WebAssembly 2.0がドラフト段階に入り、SIMD関連の多数の命令やv128データ型、関数が多値を返せる機能、大量のメモリの初期化・コピーなどが追加されました。

2023年10月から12月にかけて、Wasmランタイム側でガベージコレクション (GC) に対応する WebAssembly Garbage Collection (WasmGC) が、Chrome、Firefox、Edgeの最新版でデフォルトで有効になりました。

実装



Wasmは当初、ウェブブラウザでネイティブに近いコード実行速度を実現するために設計されましたが、現在では、ウェブブラウザの枠を超えて、より一般的な文脈や用途でも価値があると認識されています。

Wasm自体は、命令セットなどの側面を定義するだけであり、Linuxカーネルが提供するようなシステムコール(例:ファイルI/O)や、ウェブブラウザが提供するようなDOMアクセスなどは提供しません。この特性が、Wasmの安全性と可搬性の基礎となっています。アプリケーションに必要なAPIは別途定義され、Wasmランタイムがそれらを実装することで機能を提供します。この設計により、Wasmエコシステムは高い拡張性を有しています。

ウェブブラウザ



2017年11月、MozillaはMicrosoft Edge 16でWasmがデフォルトで有効になったことを発表し、「すべての主要なブラウザで」Wasmがサポートされるようになったと宣言しました。この対応には、iOSとAndroidのモバイルウェブブラウザも含まれます。2024年3月現在、99%のブラウザがWebAssembly(バージョン1.0)をサポートしており、その前身であるasm.js(Safariなどで使用できなかった)を上回っています。バージョン2.0のドラフト標準に基づくいくつかの拡張機能のサポートは変動する可能性がありますが、それでも9割以上のブラウザがすでにサポートしていると推測されます。

スタンドアローン環境とWASI



Wasmランタイム環境(RE)は、低レベルの仮想スタックマシンであり、(JVMやFlash VMと同様に)ホストアプリケーションに埋め込むことができるため、ウェブブラウザに限定されない利用方法があります。WasmtimeやWasmerのようなスタンドアロンランタイムが開発されました。

WebAssembly System Interface(WASI)は、Mozillaによって設計された、どのプラットフォームにも移植できるように設計されたシンプルなインターフェース(ABIおよびAPI)です。WASIは、例えば「ケーパビリティベースのセキュリティで制限されたファイルI/O」のようなPOSIX風の機能を提供します。他にもいくつかのABI/APIが提案されています。WASIは、CapsicumのCloudABIの影響を受けています。

Dockerの共同創業者であるソロモン・ハイクスは2019年に、「もし2008年にWasm+WASIが存在していれば、Dockerを作る必要はなかっただろう」と述べています。これは、サーバー上でのWasmがコンピューティングの未来であるということを示唆しています。

仕様



Wasmは、既存のウェブブラウザで広く使用されているJavaScriptと比較して、高速な構文解析と実行が可能なポータブルなスタックマシンとして設計されています。Wasmの仕様は、Wasmの言語仕様と実行ファイル形式を定義します。

言語



Wasmは、高水準のアセンブリ言語として設計されており、x64などのアセンブリ言語には見られない以下の特徴があります。

制御命令: ifやloopなど、直接的なJUMP命令を持たず、安全で高水準な制御フローを実現します(構造化プログラミング)。
関数: 型、ローカル変数、本体で定義され、呼び出される関数です。コードを組織化します。
ローカル変数: 関数スコープの自動変数で、get/set/tee命令でアクセスでき、疑似レジスタとして利用可能です。
値型: 値に定義される型は、i32、i64、f32、f64の4種類です。charやstringは型としてサポートされていません。また、高級言語のように関数が構造体型を直接的に扱うコードを記述することはできません。

入出力



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

フォーマット



Wasmは、バイナリフォーマットとテキストフォーマットを定義しています。フォーマットの設計方針として、Compact(コンパクト)、Modular(モジュール化)、Efficient(効率的)、Streamable(ストリーミング可能)、Parallelizable(並列処理可能)、Portable(ポータブル)を掲げています。

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

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

内部的には、Wasmコンパイラシステムは中間コードを扱うためにS式を使用しています。

SIMD



Wasmのバージョン2.0(ドラフト)には、128ビット幅のベクトル型(v128)とSIMD命令が追加されています。

連携



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

基本的な問題として、Wasmとホスト間の型システムの不一致(マーシャリング)をどのように扱うかが重要になります。

文字列



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

ツール



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

バックエンド



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

ランタイム



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

ランタイムは、ウェブブラウザへの組み込み(JavaScript実行環境からの呼び出し)や、スタンドアロンのWasmネイティブラインタイム(例:CLIにおける`$ wasmtime foo.wasm`)として存在します。

過去には、CraneliftコンパイラベースのLucetというランタイムも存在しました。

開発環境



WebAssembly Studio: WebベースのWasm向け開発環境。C言語およびRustに対応しており、オープンソースです。

ライブラリ



Qt for WebAssembly: アプリケーションフレームワークのQtをWasmに移植したものです。2018年4月現在、テクノロジープレビューとして提供されています。

参考文献



V8.dev. WebAssembly compilation pipeline.

関連項目



asm.js
Emscripten

外部リンク



公式ウェブサイト英語
WebAssembly Community Group(英語
WebAssembly Design(英語

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。