はじめに
WebAssembly
は Web ブラウザ上で実行できる効率的で軽量なバイナリ形式の技術として注目されています。
しかし、そのテキスト形式である Wat
(WebAssembly Text Format)で「Hello, World!
」を実装しようとすると、意外と手間がかかります。
本記事では、その理由を解説します。
WebAssembly での「文字列」の扱い
WebAssembly 自体には文字列型が存在しません。文字列はバイト列として表現され、通常はメモリ(単一の連続したバイト配列)上の特定の位置に保存されます。
これを操作するには、以下のような手順が必要です。
- 文字列をメモリに格納する。
- メモリのアドレスを管理する。
- 必要に応じて文字列を 1 バイトずつ処理する。
これにより、Wat
で「Hello, World!
」を表示するコードを書くのは意外と手間がかかります。
Wat で「Hello, World!」を実装
以下は、Wat
で「Hello, World!
」を出力するためのコード例です。このコードは、文字列をメモリに格納し、それをJavaScript側で取得して出力します。
(module
(memory (export "memory") 1) ;; メモリを1ページ(64KB)確保
(data (i32.const 0) "Hello, World!\00") ;; メモリの先頭に文字列データを配置
(func (export "get_hello_world_ptr") (result i32)
(i32.const 0) ;; メモリ上の文字列のアドレスを返す
)
(func (export "get_hello_world_len") (result i32)
(i32.const 13) ;; 文字列の長さを返す("Hello, World!"は13バイト)
)
)
このコードでは、以下のことをしています。
- メモリの確保:
memory
セクションで1ページ分のメモリを確保します。 - 文字列データの配置:
data
セクションを使い、文字列データをメモリに格納します。 - エクスポート関数の定義:
JavaScript
側で文字列の位置(アドレス)と長さを取得できる関数を用意します。
次に ;;
以降のコメントを消して、WebAssembly 形式に変換します。
ブラウザ上で変換したい場合は、以下のサイトでできます。WAT
の欄に上記のコードを記述し、Download
ボタンをクリックするとダウンロードできます。
WebAssembly のファイル名は hello_world.wasm
とし、これから記述するファイルと同じディレクトリに配置してください。
JavaScript 側での出力処理
Wat
単体では文字列を直接出力することはできません。JavaScript
を使ってメモリから文字列を読み取る必要があります。
fetch('hello_world.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, {}).then(results => {
const instance = results.instance;
// メモリビューを取得
const memory = new Uint8Array(instance.exports.memory.buffer);
// 文字列の位置と長さを取得
const ptr = instance.exports.get_hello_world_ptr();
const len = instance.exports.get_hello_world_len();
// メモリから文字列を読み取る
const text = new TextDecoder('utf-8').decode(memory.subarray(ptr, ptr + len));
console.log(text); // "Hello, World!"
})
);
上記のコードでは、メモリバッファを参照して文字列データを取得し、JavaScript
の console.log
で出力しています。
おわりに
本記事で見てきたように、
-
Wat
で作業すると、メモリ管理やデータ配置といった低レベルな操作が必要です。 - また、
WebAssembly
には標準ライブラリがないため、文字列操作や I/O(入力/出力)を直接扱う機能がありません。これらの機能はすべて、ホスト環境(JavaScript
など)に依存します。
そのため、Wat
で "Hello, World!"
を表示することは手間がかかります。