WebAssembly

WebAssembly（ウェブアセンブリ、公式の略称はWasm"abbreviated Wasm ... A contraction of “WebAssembly”, not an acronym, hence not using all-caps." WebAssembly Specification Release 1.1 (Draft, Mar 12, 2021) 2021-03-26閲覧）は、実行可能ファイルを表現するための可搬なバイナリコード形式（およびそれに対応するテキスト形式）を定め、同時にそのような実行可能プログラムとホスト環境との間のやりとりを容易にするためのソフトウェアインタフェースを提供するものである。

Wasmの当初の目的は、ウェブページ上で高パフォーマンスなアプリケーションを実現することであった。しかし「ウェブ特有の仮定は一切しておらず、ウェブ特有の機能を提供するわけでもないので、他の環境で同様に採用できる」としている。Wasmはオープン標準であり、あらゆるオペレーティングシステム上であらゆる言語をサポートすることを目指している。実際に、最も有名な言語のすべてが、少なくともいくらかのレベルでWasmに対応している。

Wasmは、仮想の命令セットアーキテクチャあるいはプログラミング言語の一種"At its core, WebAssembly is a virtual instruction set architecture (virtual ISA)." WebAssembly Specification Release 1.1 (Draft, Mar 12, 2021) 2021-03-26閲覧とも捉えられる。多くの場合、C/C++, Rustといったプログラミング言語のコンパイル先としてWasmバイナリが生成され、ウェブブラウザやその他のソフトウェア環境内で、スタックマシンによって実行される。ネイティブコードに近い高速さ、隔離環境でのメモリ安全な実行による安全性、仮想マシンによる可搬性やソースプログラミング言語中立性などを特徴とする"The design goals of WebAssembly are the following ... Fast: executes with near native code performance ... Safe: code is validated and executes in a memory-safe, sandboxed environment ... Hardware-independent ... Language-independent ... Platform-independent: can be embedded in browsers, run as a stand-alone VM, or integrated in other environments" WebAssembly Specification Release 1.1 (Draft, Mar 12, 2021) 2021-03-26閲覧。

Wasmは2015年に発表され、2017年3月に初めてリリースされたWebAssemblyは、2019年12月5日にW3C勧告となり、2021年の ACM SIGPLAN のプログラミング言語ソフトウェア賞を受賞した。World Wide Web Consortium (W3C) が技術標準を管理しており、有名な大企業なども加盟する非営利団体「Bytecode Alliance」が貢献している。

 歴史 
WebAssembly という命名は、1950年代にまで遡る「アセンブリ言語」の概念を想起させるためのものであり、アセンブリのようなプログラミングを、Webのクライアントサイド（つまりユーザのWebブラウザを介したユーザのコンピュータ上）で実行される世界に持ち込むことを示唆している。これを実現するために、WebAssemblyは、真のアセンブリ言語に比べて圧倒的にハードウェア非依存でなければならない。

WebAssemblyの最初のアナウンスは2015年6月17日に行われ、2016年3月15日に公開された初のデモは、主要ブラウザ (Firefox, Chromium, Google Chrome, Microsoft Edge) 上でUnityのAngry Botsを動かすものだった。前身となった技術は、Mozillaによる asm.jsと Google Native Client であり、最初の実装は asm.js の機能セットに基づいて行われた。asm.jsはすでにネイティブに近いコード実行速度を提供しており、WebAssembly非対応の環境やセキュリティ上の理由で無効化している環境での実用可能な代替とみなすことができた。

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

2017年3月にMVPの設計が完了したことが宣言され、WebAssemblyに標準対応した初のブラウザとなるFirefox 52.0がリリースされた。2017年11月、MozillaはMicrosoft EdgeがWebAssemblyに対応し、すでに対応しているChromeとFirefoxを含め、主要なブラウザすべてでサポートされたことを発表した。2018年2月には、WebAssembly Working Groupが、3つのワーキングドラフト「Core Specification」「JavaScript Interface」「Web API」を公開した。

2019年6月に、Chrome 75は、WebAssemblyスレッドが有効にされた状態でリリースされた。

2019年12月5月に、W3C勧告「WebAssembly Core Specification」が策定され、WebAssemblyは正式なウェブ標準に認定された5 December 2019 — The World Wide Web Consortium (W3C) announced today that the WebAssembly Core Specification is now an official web standard, launching a powerful new language for the Web. W3C (2019). World Wide Web Consortium (W3C) brings a new language to the Web as WebAssembly becomes a W3C Recommendation.。

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

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

 実装 
WebAssembly (Wasm) は当初、Webブラウザでネイティブに近いコード実行速度を実現するために設計されたものの、今ではWebブラウザの枠を出た、より一般的な文脈や用途でも価値があるとみなされている。

Wasm自体は命令セットなどの面を定めるだけであり、Linuxカーネルが提供するようなシステムコール（例: ファイルI/O）やWebブラウザが提供するようなDOMアクセスなどを提供しない"This document is concerned with the core ISA layer of WebAssembly. ... It does not, however, define how WebAssembly programs can interact with a specific environment they execute in" WebAssembly Specification Release 1.1 (Draft, Mar 12, 2021) 2021-03-26閲覧。安全性や可搬性はこの特徴に由来する。応用に必要なAPIは別途に定義され、Wasmランタイムがそれを実装することでそれらの機能を提供する"Instead, this specification is complemented by additional documents defining interfaces to specific embedding environments such as the Web. These will each define a WebAssembly application programming interface (API) suitable for a given environment." WebAssembly Specification Release 1.1 (Draft, Mar 12, 2021) 2021-03-26閲覧。これによってWasmエコシステムは高い拡張性を有する。

 Webブラウザ 
2017年11月にMozillaは、Microsoft Edge 16でWebAssemblyがデフォルトで有効になった後、「すべての主要なブラウザでの」Wasm対応を宣言した。この対応にはiOSとAndroidのモバイルWebブラウザも含まれる。 。99%のブラウザがWebAssembly（バージョン1.0）をサポートしており、その前身であるasm.js（Safariなどで使えなかった）を上回っている。 バージョン2.0ドラフト標準に由来するいくつかの拡張については対応度は下がりうるが、それでも9割以上のブラウザが既にサポートしていると推測される。

 スタンドアローン環境およびWASI 
Wasmのランタイム環境 (RE) は、（JVMやFlash VMと同様の）低レベルの仮想スタックマシンであり、ホストアプリケーションに埋め込むことができるため、Webブラウザにとらわれない活用の道があり、WasmtimeやWasmerといったスタンドアローンのランタイムが作られた。

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

Docker の共同創業者であるソロモン・ハイクスは2019年に、「もし2008年にWASM+WASIが存在していたらDockerを作る必要はなかっただろう、というくらい重要なものだ。サーバ上でのWebAssemblyはコンピューティングの未来だ」と書いた。

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

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

 制御命令: if や loop。直接のJUMP命令が無い、安全かつ高水準の制御フローを実現（構造化プログラミング）"Control instructions alter control flow. Control flow is structured ... well-nested constructs ... Branches can only target such constructs." WASM specification 1.0
 関数: 型・ローカル変数・ボディで定義され"func ::= {type typeidx, locals vec(valtype), body expr}"  WASM specification 1.0、call される関数。コードの組織化を実現"Code is organized into separate functions. Each function takes a sequence of values as parameters and returns a sequence of values as results."  WASM specification 1.0
 ローカル変数: 関数スコープの自動変数。get/set /tee 命令でアクセスでき疑似レジスタとして利用可能"Functions may also declare mutable local variables that are usable as virtual registers." WASM specification 1.0

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

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

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

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

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

+ Cソースコードおよび対応するWebAssembly C（変換元）  WASMテキストフォーマット（中間表現）  WASMバイナリフォーマット（16進数で表記）int factorial(int n) {
  if (n == 0)
    return 1;
  else
    return n * factorial(n-1);
} 
(func (param i64) (result i64)
  local.get 0
  i64.eqz
  if (result i64)
      i64.const 1
  else
      local.get 0
      local.get 0
      i64.const 1
      i64.sub
      call 0
      i64.mul
  end) 
20 00
42 00
51
04 7e
42 01
05
20 00
20 00
42 01
7d
10 00
7e
0b

サンプルのソースコードはGitHubのWebAssemblyプロジェクトより https://github.com/WebAssembly/design/blob/master/TextFormat.md

内部的には、wasmコンパイラシステムは中間コードを扱うためにS式を使用している。サンプルを以下に示す。http://cultureofdevelopment.com/blog/build-your-first-thing-with-web-assembly/

(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)
    )
  )
)

 SIMD 
Wasmのバージョン 2.0（ドラフト）には128ビット幅のベクトル型（v128）と、SIMD命令が追加されている"2.4.2. Vector Instructions    Vector instructions (also known as SIMD instructions, single data multiple value) provide basic operations over values of vector type." 

W3C. (2022). WebAssembly Core Specification Editor’s Draft, 2 March 2022.。

 連携 
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 (後述)を使用するhttps://github.com/WebAssembly/binaryen。なお、LLVMのWebAssembly実装とFastcompのWebAssembly実装は別物である。
 GCC asm.js backend - asm.js及びWebAssemblyに対応しているhttps://github.com/pipcet/asmjs/blob/everything/asmjs.org。
 LLVM - WebAssemblyバックエンドを持ち、WebAssemblyバイナリを直接出力できる。また、LLDによるWebAssemblyバイナリのリンクも可能。LLVM 8.0で正式に対応した「LLVM 8.0」登場、WebAssemblyを正式サポート OSDN 2019年3月22日。

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

 ランタイム 
仮想マシンの命令セットであるWASMはコンピュータの実行ファイルではないため、そのまま機械語として実行はできない。そのためWASMファイルはランタイムを介し解釈・実行される。ランタイムにはインタプリタ/JITコンパイラ/AOTコンパイラがあり用途に合わせて選択される。
+表. WASMランタイム実行環境エンジン/ランタイムコンパイラGoogle Chrome & Node.jsV8Liftoff (baseline)"V8 first compiles a WebAssembly module with its baseline compiler, Liftoff." V8.dev. WebAssembly compilation pipeline. + TurboFan (optimizing)"This is why, as soon as Liftoff compilation is finished, V8 immediately starts to "tier up" the module by recompiling all functions with TurboFan, the optimizing compiler in V8 for both WebAssembly and JavaScript." V8.dev. WebAssembly compilation pipeline. Mozilla FirefoxSpiderMonkey"SpiderMonkey is the JavaScript and WebAssembly engine in Firefox." wasmtime (2018). Cranelift in SpiderMonkey.rabaldr (baseline) + BaldrMonkey (optimizing, backed by IonMonkey)wasmtime"A standalone runtime for WebAssembly" bytecodealliance/wasmtime. RAEDME.md. -Cranelift"Wasmtime is built on the optimizing Cranelift code generator to quickly generate high-quality machine code at runtime." bytecodealliance/wasmtime. RAEDME.md.Wasmer"The leading WebAssembly Runtime supporting WASI and Emscripten" wasmerio/wasmer. About. -pluggable (LLVM, Cranelift)"Wasmer supports different compilation frameworks to best suit your needs (LLVM, Cranelift...)." wasmerio/wasmer. About.
ランタイムはウェブブラウザへの組み込み（JavaScript実行環境からの呼び出し）や独立したWASMネイティブランタイム (例: CLIにおける $ wasmtime foo.wasm" you can execute a WebAssembly file" wastime. Using the wasmtime CLI.) として存在する。

かつて存在したランタイムにはCraneliftコンパイラベース"Lucet uses, and is developed in collaboration with, the Bytecode Alliance's Cranelift code generator." bytecodealliance/lucet. README.md.のLucetがある"Lucet is a native WebAssembly compiler and runtime." bytecodealliance/lucet. README.md.。

 開発環境 

 WebAssembly Studio - WebベースのWebAssembly向け開発環境。C言語及びRustに対応している。オープンソースAw, all grown up: Mozilla moves WebAssembly into sparsely furnished Studio apartment The Register 2018年4月11日。

 ライブラリ 

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

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


 脚注 

 関連項目 
 asm.js
 Emscripten

外部リンク

 WebAssembly Community Group 
 WebAssembly Design 

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