import * as assert from '../assert.js'; import Builder from '../Builder.js'; const wasmModuleWhichImportJS = () => { const builder = (new Builder()) .Type().End() .Import() .Function("imp", "func", { params: ["i32"] }) .Table("imp", "table", { initial: 1, maximum: 1, element: "anyfunc"}) .End() .Function().End() .Export() .Function("changeCounter") .Function("callFunc") .End() .Code() .Function("changeCounter", { params: ["i32", "i32"] }) .I32Const(42) .GetLocal(0) .I32Add() .GetLocal(1) .CallIndirect(0, 0) // Calls table[0](param[0] + 42). .End() .Function("callFunc", { params: ["i32"] }) .GetLocal(0) .Call(0) // Calls func(param[0] + 42) .End() .End(); const bin = builder.WebAssembly().get(); const module = new WebAssembly.Module(bin); return module; }; const makeTable = () => { return new WebAssembly.Table({initial: 1, maximum: 1, element: "anyfunc"}); }; (function MonomorphicImport() { let counter = 0; const counterSetter = v => counter = v; const table = makeTable(); const module = wasmModuleWhichImportJS(); const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table} }); table.set(0, instance.exports.callFunc); for (let i = 0; i < 4096; ++i) { // Invoke this a bunch of times to make sure the IC in the wasm -> JS stub works correctly. instance.exports.changeCounter(i, 0); assert.eq(counter, i + 42); } })(); (function Polyphic2Import() { let counterA = 0; let counterB = undefined; const counterASetter = v => counterA = v; const counterBSetter = v => counterB = { valueB: v }; const module = wasmModuleWhichImportJS(); const tableA = makeTable(); const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA} }); tableA.set(0, instanceA.exports.callFunc); const tableB = makeTable(); const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB} }); tableB.set(0, instanceB.exports.callFunc); for (let i = 0; i < 2048; ++i) { instanceA.exports.changeCounter(i, 0); assert.isA(counterA, "number"); assert.eq(counterA, i + 42); instanceB.exports.changeCounter(i, 0); assert.isA(counterB, "object"); assert.eq(counterB.valueB, i + 42); } })(); (function VirtualImport() { const counterSetters = [ v => counters[0] = v, v => counters[1] = v + 1, v => counters[2] = v + 2, v => counters[3] = v + 3, v => counters[4] = v + 4, v => counters[5] = v + 5, v => counters[6] = v + 6, v => counters[7] = v + 7, v => counters[8] = v + 8, v => counters[9] = v + 9, ]; const num = counterSetters.length; let counters = counterSetters.map(() => 0); assert.eq(counters.length, num); const module = wasmModuleWhichImportJS(); let instances = []; for (let i = 0; i < num; ++i) { let table = makeTable(); instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table} }); table.set(0, instances[i].exports.callFunc); } for (let i = 0; i < 2048; ++i) { for (let j = 0; j < num; ++j) { instances[j].exports.changeCounter(i, 0); assert.isA(counters[j], "number"); assert.eq(counters[j], i + 42 + j); } } })();