WebAssembly APIについてまとめる
WebAssembly Moduleの読み込み
Streaming読み込み
Firefox 58
からの新機能で、WebAssemblyモジュールをソースから直接コンパイルおよびインスタンス化する機能が追加されている
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
(obj) => obj.instance.exports.exported_func(),
);
メリット
- バイトコードを直接
Module
/Instance
インスタンスに変換できる-
fetch()
からのResponse
をArrayBuffer
に変換する必要がない
-
通常読み込み
上記のStreamingに
- 対応していない
- 使用したくない事情があるとき
代わりに
こっちはバイトコードに直接アクセスできないため、
- WebAssembly Moduleを
fetch()
関数で取得し - 取得した
Response
をArrayBuffer
にする
という手順が必要
fetch("simple.wasm")
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
.then((results) => {
results.instance.exports.exported_func();
});
WebAssemblyでのメモリの仕様
WebAssemblyの低レベルのメモリのモデルは
線形メモリと呼ばれる
- 型なし
- 連続したバイト列
として表現される。
それらのメモリに格納されたデータは
モジュール内のロード、ストア命令を使用して読み書きされる
このメモリモデルだと、任意のロード、ストア命令は線形メモリ全体の任意のバイトにアクセス可能。
(ここなんかアセンブラ動かしてるみたいで面白そう)
ただし、利用可能なメモリ範囲がプロセス全体に及ぶネイティブのC/C++プログラムとは異なる。
WebAssemblyインスタンスがアクセス可能なメモリの範囲は
WebAssembly Memoryオブジェクトが含む、特定(潜在的に非常に小さい)範囲に制限されている
Memory
インスタンスはリサイズ可能なArrayBuffer
(または共有メモリの場合はSharedArrayBuffer
)とみなすことが可能なため、ArrayBuffer
と同様にして、多くの独立したMemory
オブジェクトを作成可能である。
また、Memory
オブジェクトは以下のようにして作成できる
new WebAssembly.Memory({
initial: 10, // 初期サイズ(必須)
maximum: 100 // 最大サイズ(省略可能)
})
initial
とmaximum
の単位はWebAssemblyページ
でこれらが64KBに固定されている。
つまり上記のインスタンスは、
- 初期サイズ:640KB
- 最大サイズ:6.4MB
であることを意味する
WebAssemblyメモリが持つバイト列は
ArrayBufferとしてBuffer Getter/Setterから公開されているため
const memory = new WebAssembly.Memory({
initial: 10, // 初期サイズ(必須)
maximum: 100 // 最大サイズ(省略可能)
})
new Uint32Array(memory.buffer)[0] = 42
// 線形メモリの先頭ワードに直接、42を書き込む
こういうコードを書く
メモリ拡張
メモリインスタンスは、grow()
を呼び出すことが拡張可能
try {
memory.grow(1) // 引数はWebAssemblyページ単位で指定
} catch(e){
// Memoryインスタンス作成時に最大値を指定していて、
// それを超えた拡張をするとエラーがでる
}
関数と同様にして、線形メモリは
モジュール内で定義したり、インポートすることも可能
また、任意でメモリをエクスポートすることも可能
これは、JavaScriptがWebAssemblyインスタンスに対して新しく作成したWebAssembly.Memory
をインポートで渡したり、
Memory
のエクスポートから(Instance.exportsを介して)受け取りが可能
参考サイト