blob: 7230a7c68941aee5a3320acef244c99648f7f227 [file] [log] [blame]
import Builder from '../Builder.js'
import * as assert from '../assert.js'
{
function makeInstance() {
const tableDescription = {initial: 1, element: "funcref"};
const builder = new Builder()
.Type()
.Func([], "void")
.End()
.Import()
.Table("imp", "table", tableDescription)
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params:["i32"], ret:"void"})
.GetLocal(0) // parameter to call
.GetLocal(0) // call index
.CallIndirect(0, 0) // calling function of type [] => 'void'
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
const table = new WebAssembly.Table(tableDescription);
return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
}
function makeInstance2(f) {
const builder = new Builder()
.Type()
.End()
.Import()
.Function("imp", "f", {params:[], ret:"void"})
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params: [], ret: "void" })
.Call(0)
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
return new WebAssembly.Instance(module, {imp: {f}});
}
const {instance: i1, table: t1} = makeInstance();
const foo = i1.exports.foo;
let called = false;
let shouldThrow = false;
const i2 = makeInstance2(function() {
called = true;
if (shouldThrow)
throw new Error("Threw");
});
t1.set(0, i2.exports.foo);
for (let i = 0; i < 1000; ++i) {
foo(0);
assert.eq(called, true);
called = false;
}
shouldThrow = true;
for (let i = 0; i < 1000; ++i) {
assert.throws(() => foo(0), Error, "Threw");
assert.eq(called, true);
called = false;
}
}
{
function makeInstance() {
const tableDescription = {initial: 1, element: "funcref"};
const builder = new Builder()
.Type()
.Func(["i32"], "void")
.End()
.Import()
.Table("imp", "table", tableDescription)
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params:["i32", "i32"], ret:"void"})
.GetLocal(1) // parameter to call
.GetLocal(0) // call index
.CallIndirect(0, 0) // calling function of type ['i32'] => 'void'
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
const table = new WebAssembly.Table(tableDescription);
return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
}
function makeInstance2(memory, f) {
const builder = new Builder()
.Type()
.End()
.Import()
.Function("imp", "f", {params:['i32', 'i32'], ret:"void"})
.Memory("imp", "memory", memoryDescription)
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params: ["i32"], ret: "void" })
.GetLocal(0)
.GetLocal(0)
.I32Load(2, 0)
.Call(0)
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
return new WebAssembly.Instance(module, {imp: {f, memory}});
}
const {instance: i1, table: t1} = makeInstance();
const foo = (memOffset) => i1.exports.foo(0, memOffset);
const memoryDescription = {initial:1};
const mem = new WebAssembly.Memory(memoryDescription);
let called = false;
const pageSize = 64 * 1024;
let buf = new Uint32Array(mem.buffer);
const i2 = makeInstance2(mem, function(i, value) {
assert.eq(i & 3, 0);
assert.eq(buf[i/4], value);
called = true;
});
t1.set(0, i2.exports.foo);
for (let i = 0; i < pageSize/4; ++i) {
buf[i] = i+1;
}
for (let i = 0; i < pageSize/4; ++i) {
foo(i*4);
assert.eq(called, true);
called = false;
}
for (let i = pageSize/4; i < 2*pageSize/4; ++i) {
assert.throws(() => foo(i*4), WebAssembly.RuntimeError, "Out of bounds memory access");
assert.eq(called, false);
}
}
{
function makeInstance() {
const tableDescription = {initial: 1, element: "funcref"};
const builder = new Builder()
.Type()
.Func(["i32"], "void")
.End()
.Import()
.Table("imp", "table", tableDescription)
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params:["i32", "i32"], ret:"void"})
.GetLocal(1) // parameter to call
.GetLocal(0) // call index
.CallIndirect(0, 0) // calling function of type ['i32'] => 'void'
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
const table = new WebAssembly.Table(tableDescription);
return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
}
function makeInstance2(memory, f) {
const builder = new Builder()
.Type()
.End()
.Import()
.Function("imp", "f", {params:['i32', 'i32'], ret:"void"})
.Memory("imp", "memory", memoryDescription)
.End()
.Function().End()
.Export()
.Function("foo")
.End()
.Code()
.Function("foo", {params: ["i32"], ret: "void" })
.GetLocal(0)
.GetLocal(0)
.I32Load(2, 0)
.Call(0)
.Return()
.End()
.End();
const bin = builder.WebAssembly().get();
const module = new WebAssembly.Module(bin);
return new WebAssembly.Instance(module, {imp: {f, memory}});
}
function exportImport(f) {
let builder = (new Builder())
.Type().End()
.Import()
.Function("imp", "f", {params: ['i32'], ret:"void"})
.End()
.Function().End()
.Export()
.Function("func", {module: "imp", field: "f"})
.End()
.Code().End();
return (new WebAssembly.Instance(new WebAssembly.Module(builder.WebAssembly().get()), {imp: {f}})).exports.func;
}
const {instance: i1, table: t1} = makeInstance();
const foo = (memOffset) => i1.exports.foo(0, memOffset);
const memoryDescription = {initial:1};
const mem = new WebAssembly.Memory(memoryDescription);
let called = false;
const pageSize = 64 * 1024;
let buf = new Uint32Array(mem.buffer);
const i2 = makeInstance2(mem, function(i, value) {
assert.eq(i & 3, 0);
assert.eq(buf[i/4], value);
called = true;
});
const exportedImport = exportImport(function(offset) {
i2.exports.foo(offset);
});
t1.set(0, exportedImport);
for (let i = 0; i < pageSize/4; ++i) {
buf[i] = i+1;
}
for (let i = 0; i < pageSize/4; ++i) {
foo(i*4);
assert.eq(called, true);
called = false;
}
for (let i = pageSize/4; i < 2*pageSize/4; ++i) {
assert.throws(() => foo(i*4), WebAssembly.RuntimeError, "Out of bounds memory access");
assert.eq(called, false);
}
}