エクスポートされた WebAssembly 関数
エクスポートされた WebAssembly 関数は WebAssembly 関数が JavaScript でどのように表現されるのか、この記事では、もう少し詳しく説明します。
エクスポートされた...とは?
エクスポートされた WebAssembly 関数は、 WebAssembly 関数を表現する JavaScript の単なるラッパーです。呼び出されると、バックグラウンドでいくつかの動作を行います。引数を Wasm で使える型に(例えば、 JavaScript の数値を Int32 に)変換し、Wasm モジュール内の関数に渡し、実行し、結果を変換して JavaScript 側に戻します。
エクスポートされた WebAssembly 関数は次の 2 つの方法で取得できます。
- 既存のテーブルの
Table.prototype.get()
を呼び出す。 - Wasm モジュールインスタンスの
Instance.exports
を通してエクスポートされた関数にアクセスする。
いずれにしても、同じ種類の内在する関数のラッパーを取得できます。 JavaScript からみると、すべての Wasm 関数は JavaScript の関数のようにみえます。しかし、これは Wasm 関数オブジェクトインスタンスによってカプセル化されており、アクセスする方法は限られています。
例
物事を明らかにするために例を見ていきましょう(例は GitHub の table-set.html と 動作例、Wasm の テキスト表現 を参照してください)。
const otherTable = new WebAssembly.Table({ element: "anyfunc", initial: 2 });
WebAssembly.instantiateStreaming(fetch("table.wasm")).then((obj) => {
const tbl = obj.instance.exports.tbl;
console.log(tbl.get(0)()); // 13
console.log(tbl.get(1)()); // 42
otherTable.set(0, tbl.get(0));
otherTable.set(1, tbl.get(1));
console.log(otherTable.get(0)());
console.log(otherTable.get(1)());
});
ここでは、WebAssembly.Table
コンストラクターを使用して JavaScript からテーブル (otherTable
) を作成し、table.wasm
をページに読み込むために WebAssembly.instantiateStreaming()
ユーティリティ関数を使用しています。
そのあと、モジュールからエクスポートされた関数を取得し、関数の参照を tbl.get()
を通して取り出し、それぞれを実行した結果をコンソールに出力します。次に、 set()
を使用して、tbl
テーブルと同じ関数への参照を otherTable
テーブルに含まれるようにします。
確認するために、otherTable
から参照を取得し直し、その結果もコンソールに出力します(同じ結果が得られます)。
それらは本物の関数です
前の例で、Table.prototype.get()
のそれぞれの返値はエクスポートされた WebAssembly 関数でした。まさに私たちが話していたことです。
これらは WebAssembly 関数のラッパーであるのに加えて本物の JavaScript 関数であることに注意してください。上の例を WebAssembly に対応しているブラウザーで読み込み、以下の行をコンソールで実行してみてください。
const testFunc = otherTable.get(0);
typeof testFunc;
結果として関数が返されます。この関数は他の JavaScript の関数と同じように扱うことができます。例えば call()
や bind()
などです。 testFunc.toString()
は興味深い結果を返します。
function 0() { [native code] }
これで、よりラッパーの性質がよくわかると思います。
エクスポートされた WebAssembly 関数について他の注意事項を挙げます。