エクスポートされた 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 関数について他の注意事項を挙げます。