| 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(["i32"], "void") |
| .End() |
| .Import() |
| .Table("imp", "table", tableDescription) |
| .End() |
| .Function().End() |
| .Export() |
| .Function("foo") |
| .End() |
| .Code() |
| .Function("foo", 0 /*['i32'] => 'void'*/) |
| .GetLocal(0) // parameter to call |
| .GetLocal(0) // call index |
| .CallIndirect(0, 0) // calling function of type ['i32'] => 'i32' |
| .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}; |
| } |
| |
| const {instance: i1, table: t1} = makeInstance(); |
| const {instance: i2, table: t2} = makeInstance(); |
| t2.set(0, i1.exports.foo); |
| t1.set(0, i2.exports.foo); |
| |
| function assertOverflows(instance) { |
| let stack; |
| try { |
| instance.exports.foo(0) |
| } catch(e) { |
| stack = e.stack; |
| } |
| stack = stack.split("\n"); |
| assert.truthy(stack.length > 50); |
| for (let i = 0; i < 50; ++i) { |
| let item = stack[stack.length - i - 1]; |
| assert.eq(item, '<?>.wasm-function[0]@[wasm code]'); |
| } |
| } |
| assertOverflows(i1); |
| assertOverflows(i2); |
| |
| } |
| |
| { |
| 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:['i32'], ret:"void"}) |
| .End() |
| .Function().End() |
| .Export() |
| .Function("foo") |
| .End() |
| .Code() |
| .Function("foo", {params: [], ret: "void" }) |
| .I32Const(0) |
| .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; |
| const i2 = makeInstance2(i1.exports.foo); |
| t1.set(0, i2.exports.foo); |
| |
| function assertThrows(instance) { |
| let stack; |
| try { |
| instance.exports.foo(); |
| } catch(e) { |
| stack = e.stack; |
| } |
| assert.truthy(stack); |
| |
| stack = stack.split("\n"); |
| assert.truthy(stack.length > 50); |
| const one = '<?>.wasm-function[1]@[wasm code]'; |
| const zero = '<?>.wasm-function[0]@[wasm code]'; |
| let currentIndex = (one === stack[stack.length - 1]) ? 1 : 0; |
| for (let i = 0; i < 50; ++i) { |
| let item = stack[stack.length - 1 - i]; |
| if (currentIndex === 1) { |
| assert.eq(item, one); |
| currentIndex = 0; |
| } else { |
| assert.eq(currentIndex, 0); |
| assert.eq(item, zero); |
| currentIndex = 1; |
| } |
| } |
| } |
| |
| for (let i = 0; i < 20; ++i) { |
| assertThrows(i2); |
| assertThrows(i1); |
| } |
| |
| for (let i = 0; i < 20; ++i) { |
| assertThrows(i1); |
| assertThrows(i2); |
| } |
| } |
| |
| { |
| function test(numArgs) { |
| function makeSignature() { |
| let args = []; |
| for (let i = 0; i < numArgs; ++i) { |
| args.push("i32"); |
| } |
| return {params: args}; |
| } |
| function makeInstance(f) { |
| let builder = new Builder() |
| .Type() |
| .Func([], "void") |
| .End() |
| .Import() |
| .Function("imp", "f", makeSignature()) |
| .End() |
| .Function().End() |
| .Export() |
| .Function("foo") |
| .End() |
| .Code() |
| .Function("foo", {params:[], ret:"void"}); |
| for (let i = 0; i < numArgs; ++i) { |
| builder = builder.I32Const(i); |
| } |
| |
| builder = builder.Call(0).Return().End().End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| return new WebAssembly.Instance(module, {imp: {f}}); |
| } |
| |
| function f(...args) { |
| assert.eq(args.length, numArgs); |
| for (let i = 0; i < args.length; ++i) |
| assert.eq(args[i], i); |
| |
| instance.exports.foo(); |
| } |
| let instance = makeInstance(f); |
| |
| let stack; |
| try { |
| instance.exports.foo(); |
| } catch(e) { |
| stack = e.stack; |
| } |
| assert.truthy(stack.split("\n").length > 25); |
| } |
| |
| for (let i = 0; i < 70; ++i) { |
| let r = Math.random() * 1000 | 0; |
| test(r); |
| } |
| |
| test(20); |
| test(20); |
| test(1000); |
| test(2); |
| test(1); |
| test(0); |
| test(700); |
| test(433); |
| test(42); |
| } |