WebAssemblyハンドブック

編集

WebAssemblyとは

編集

WebAssembly(略称:Wasm)は、モダンなウェブブラウザで動作する低レベルのバイナリフォーマットです。C++、Rust、C#などの言語からコンパイルされ、ネイティブに近いパフォーマンスを実現します。

主な特徴

編集
  • 高速実行
  • 型安全
  • メモリ安全
  • プラットフォーム非依存
  • 複数言語サポート

基本概念

編集

モジュール

編集

WebAssemblyのコードは「モジュール」として組織化されます。各モジュールには関数、メモリ、テーブルなどが含まれます。

基本的なモジュールの例(WAT形式):

(module
  (func $add (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add)
  (export "add" (func $add)))
WAT形式
WebAssembly Text Format

メモリモデル

編集

WebAssemblyは線形メモリモデルを採用しています。メモリは連続したバイト配列として表現されます。

数値型

編集
  • i32: 32ビット整数
  • i64: 64ビット整数
  • f32: 32ビット浮動小数点
  • f64: 64ビット浮動小数点

開発環境のセットアップ

編集

必要なツール

編集
  • Emscripten: C/C++からWebAssemblyへのコンパイラ
  • wasm-pack: RustのWebAssemblyビルドツール
  • wat2wasm: テキスト形式からバイナリへの変換

インストール例(Unix系システム):

# Emscriptenのインストール
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

基本的な使い方

編集

C++からのコンパイル例

編集

まず、簡単なC++プログラムを作成します:

math.cpp
#include <emscripten/bind.h>

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

EMSCRIPTEN_BINDINGS(math_module) {
    emscripten::function("factorial", &factorial);
}
コンパイルコマンド:
em++ math.cpp -o math.js -s WASM=1 -s EXPORTED_FUNCTIONS=['_factorial'] -s EXPORTED_RUNTIME_METHODS=['ccall','cwrap']

JavaScriptからの利用

編集
// HTMLでの読み込み
<script src="math.js"></script>
<script>
Module.onRuntimeInitialized = async () => {
    const result = Module.ccall(
        'factorial',     // 関数名
        'number',        // 戻り値の型
        ['number'],      // 引数の型
        [5]             // 引数の値
    );
    console.log(`5の階乗: ${result}`); // 出力: 120
};
</script>

メモリ管理

編集

線形メモリの操作

編集

WebAssemblyのメモリは、連続したバイト配列として表現されます:

// メモリの確保と操作
(module
  (memory 1)  // 1ページ(64KB)のメモリを確保
  (func $storeValue (param $addr i32) (param $value i32)
    local.get $addr
    local.get $value
    i32.store)
  (export "storeValue" (func $storeValue)))

JavaScriptとのメモリ共有

編集
const memory = new WebAssembly.Memory({ initial: 1 });
const buffer = new Uint8Array(memory.buffer);

// メモリへの書き込み
buffer[0] = 42;

// WebAssembly側での読み取り
(func $readByte (param $addr i32) (result i32)
  local.get $addr
  i32.load8_u)

JavaScriptとの連携

編集

関数のインポート

編集
(module
  ;; JavaScriptの関数をインポート
  (import "console" "log" (func $log (param i32)))
  
  (func $doSomething
    i32.const 42
    call $log)
  
  (export "doSomething" (func $doSomething)))

JavaScript側の実装

編集
const importObject = {
    console: {
        log: function(value) {
            console.log(value);
        }
    }
};

WebAssembly.instantiateStreaming(fetch('example.wasm'), importObject)
    .then(obj => {
        obj.instance.exports.doSomething();
    });

実践的なユースケース

編集

画像処理の例

編集

グレースケール変換を行う簡単な例:

// C++
#include <emscripten/bind.h>
#include <vector>

void grayscale(std::vector<unsigned char>& pixels) {
    for (size_t i = 0; i < pixels.size(); i += 4) {
        unsigned char r = pixels[i];
        unsigned char g = pixels[i + 1];
        unsigned char b = pixels[i + 2];
        unsigned char gray = (r + g + b) / 3;
        
        pixels[i] = gray;     // R
        pixels[i + 1] = gray; // G
        pixels[i + 2] = gray; // B
        // Alpha値(pixels[i + 3])はそのまま
    }
}

EMSCRIPTEN_BINDINGS(image_module) {
    emscripten::function("grayscale", &grayscale);
    emscripten::register_vector<unsigned char>("Vector<unsigned char>");
}

パフォーマンスの最適化

編集

最適化テクニック

編集
  • ループの最適化
  • メモリアクセスパターンの改善
  • SIMD命令の活用

SIMD例

編集
// SIMDを使用した最適化例(WAT形式)
(module
  (func $addVectors (param $a i32) (param $b i32) (param $len i32)
    (local $i i32)
    (local.set $i (i32.const 0))
    (loop $loop
      ;; 4要素ずつ処理
      (v128.store
        (local.get $a)
        (f32x4.add
          (v128.load (local.get $a))
          (v128.load (local.get $b))))
      
      (local.set $a (i32.add (local.get $a) (i32.const 16)))
      (local.set $b (i32.add (local.get $b) (i32.const 16)))
      (local.set $i (i32.add (local.get $i) (i32.const 4)))
      
      (br_if $loop
        (i32.lt_u (local.get $i) (local.get $len)))))

ツールとエコシステム

編集

主要なツール

編集
  • wasm-bindgen: Rust-WebAssembly連携
  • wabt: WebAssemblyバイナリツールキット
  • Binaryen: コンパイラインフラストラクチャ
  • wasm-pack: Rustパッケージング
  • wasmer: スタンドアロンランタイム

デバッグツール

編集
  • Chrome DevTools
  • Firefox WebAssembly デバッガー
  • wat2wasm: テキスト形式の検証

パフォーマンス分析

編集
  • Chrome Performance Tools
  • WebAssembly Studio
  • Wasmtime

外部リンク

編集
 
Wikipedia
ウィキペディアWebAssemblyの記事があります。