メモリモデル
リニアメモリ
各 Wasm モジュールインスタンスは最大1つのリニアメモリを持ちます(multi-memory プロポーザルにより複数持つことも可能です)。リニアメモリは連続したバイト配列であり、Wasm の load/store 命令によってアクセスされます。
アロケーション
- 初期サイズはモジュール内で指定されます(例: 1ページ = 64 KiB)
memory.growにより、指定したページ数だけメモリを拡張できます- 最大サイズはモジュール内で指定するか、
--max-memoryで制限できます
ガードページ
zwasm はリニアメモリの先に 4 GiB + 64 KiB の PROT_NONE 領域を確保します。範囲外アクセスはこのガード領域に到達し、シグナルハンドラによって捕捉されて Wasm トラップに変換されます。これにより、ほとんどのメモリ操作で命令ごとの境界チェックが不要になります。
アドレッシング
すべてのメモリアドレスは u33 演算(32ビットアドレス + 32ビットオフセット)を使用し、オーバーフローを防止します。これにより、address + offset がラップアラウンドして有効なメモリにアクセスしてしまうことがなくなります。
GC ヒープ
GC プロポーザルはマネージドヒープオブジェクト(structs、arrays、i31ref)を導入します。これらは zwasm が管理する別のアリーナに存在します:
- アリーナアロケータ: オブジェクトは事前に確保されたアリーナから割り当てられます
- 適応的しきい値: GC コレクションはアロケーション圧に基づいてトリガーされます
- リファレンスエンコーディング: オペランドスタック上の GC リファレンスはタグ付き u64 値を使用します
GC オブジェクトはリニアメモリからアクセスできず、その逆も同様です。これらは別のアドレス空間に存在します。
アロケータのパラメータ化
zwasm はロード時に std.mem.Allocator を受け取ります。すべての内部アロケーション(モジュールメタデータ、レジスタ IR、テーブルなど)はこのアロケータを経由します。リニアメモリ自体はガードページのサポートのために mmap を直接使用します。
これにより、以下のような使い方が可能です:
- 通常の用途には汎用アロケータを使用する
- バッチ処理(ロード、実行、全解放)にはアリーナアロケータを使用する
- メモリ使用量の監視にはトラッキングアロケータを使用する
- 組み込み/制約のある環境には固定バッファアロケータを使用する
メモリ制限
| リソース | デフォルト制限 | CLI フラグ |
|---|---|---|
| リニアメモリ | モジュール定義の最大値 | --max-memory <bytes> |
| コールスタック深度 | 1024 | 設定不可 |
| オペランドスタック | 固定サイズ | 設定不可 |
| GC ヒープ | 無制限(アリーナ) | 設定不可 |