blob: c6c03201353be1f1b37c7fc8fa9f6df2c0f3fa90 [file] [log] [blame]
import Builder from '../Builder.js';
import * as assert from '../assert.js';
function exportImport(type) {
let builder = (new Builder())
.Type().End()
.Import()
.Function("imp", "f", type)
.End()
.Function().End()
.Export()
.Function("func", {module: "imp", field: "f"})
.End()
.Code().End();
return new WebAssembly.Module(builder.WebAssembly().get());
}
{
let type = { params: ["i32"], ret: "i32" };
let module = exportImport(type);
let called = false;
let foo = (i) => {
called = true;
return i + 42;
};
let instance = new WebAssembly.Instance(module, {imp: {f: foo}});
assert.truthy(instance.exports.func !== foo);
for (let i = 0; i < 100; i++) {
let r1 = instance.exports.func(i);
assert.truthy(called);
called = false;
let r2 = foo(i);
called = false;
assert.eq(r1, r2);
}
{
let builder = (new Builder())
.Type().End()
.Import()
.Function("imp", "f", {params: []})
.End()
.Function().End()
.Code().End();
let module = new WebAssembly.Module(builder.WebAssembly().get());
// This should not type check.
assert.throws(() => new WebAssembly.Instance(module, {imp: {f: instance.exports.func}}), WebAssembly.LinkError, "imported function imp:f signature doesn't match the provided WebAssembly function's signature");
}
{
assert.truthy(typeof instance.exports.func === "function", "is_function bytecode should handle wrapper function.");
let value = typeof instance.exports.func;
assert.eq(value, "function", "the result of typeof should be 'function'");
}
}
{
const tableDescription = {element: "funcref", initial: 2};
function makeInstance(type, imp) {
const builder = new Builder()
.Type()
.Func(["i32"], "i32")
.Func(["i32", "i32"], "i32")
.End()
.Import()
.Table("imp", "table", tableDescription)
.Function("imp", "f1", {params: ["i32"], ret:"i32"})
.Function("imp", "f2", {params: ["i32", "i32"], ret:"i32"})
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Element()
.Element({offset: 0, functionIndices: [0, 1]})
.End()
.Code()
.Function("foo", 1)
.GetLocal(1) // parameter to call
.GetLocal(0) // call index
.CallIndirect(0, 0) // calling function of type ['i32'] => 'i32'
.Return()
.End()
.End();
let module = new WebAssembly.Module(builder.WebAssembly().get());
return new WebAssembly.Instance(module, imp);
}
function Bar(){};
noInline(Bar);
let called = false;
let foo = (i) => {
called = true;
new Bar;
return i*42;
}
let table = new WebAssembly.Table(tableDescription);
let inst = makeInstance({params:['i32'], ret:"i32"}, {imp: {f1: foo, f2:foo, table}});
for (let i = 0; i < 1000; i++) {
let r1 = inst.exports.foo(0, i);
assert.truthy(called);
called = false;
let r2 = foo(i);
assert.truthy(called);
called = false;
assert.eq(r1, r2);
}
for (let i = 0; i < 1000; i++) {
assert.throws(() => inst.exports.foo(1, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
assert.truthy(!called);
}
for (let i = 0; i < 1000; i++) {
let r1 = table.get(0)(i);
table.set(0, table.get(0)); // just make sure setting a wrapper function works.
assert.truthy(called);
called = false;
let r2 = table.get(1)(i);
assert.truthy(called);
called = false;
assert.eq(r1, r2);
}
{
let nextInst = makeInstance({params:['i32'], ret:"i32"}, {imp: {f1: table.get(0), f2:inst.exports.foo, table}});
for (let i = 0; i < 1000; i++) {
let r1 = nextInst.exports.foo(0, i);
assert.truthy(called);
called = false;
let r2 = foo(i);
assert.truthy(called);
called = false;
assert.eq(r1, r2);
}
for (let i = 0; i < 1000; i++) {
assert.throws(() => nextInst.exports.foo(1, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
assert.truthy(!called);
}
for (let i = 0; i < 1000; i++) {
let r1 = table.get(1)(0, i);
assert.truthy(called);
called = false;
let r2 = foo(i);
assert.truthy(called);
called = false;
assert.eq(r1, r2);
}
}
}