blob: 3ebb70c7cf5bea5ac12a1d6d82bb6c41b9eafa18 [file] [edit]
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"
function checkAll(table, expected, label) {
assert.eq(table.length, expected.length, label)
for (let i = 0; i < table.length; ++i) {
const v = table.get(i)
const msg = `${label}[${i}]`
if (expected[i] === null)
assert.eq(v, null, msg)
else if (expected[i] === undefined)
assert.eq(v, undefined, msg)
else
assert.eq(v, expected[i], msg)
}
}
const helperWat = `
(module
(func (export "f") (result i32) (i32.const 42))
)
`
const callIndirectWat = `
(module
(type $sig (func (result i32)))
(import "env" "table" (table 4 funcref))
(func (export "call") (param i32) (result i32)
(call_indirect (type $sig) (local.get 0)))
)
`
const callIndirectGrowableWat = `
(module
(type $sig (func (result i32)))
(import "env" "table" (table 4 8 funcref))
(func (export "call") (param i32) (result i32)
(call_indirect (type $sig) (local.get 0)))
)
`
async function testDefaultsAndNull() {
checkAll(new WebAssembly.Table({ element: "externref", initial: 4 }),
[undefined, undefined, undefined, undefined], "externref default")
checkAll(new WebAssembly.Table({ element: "externref", initial: 4 }, null),
[null, null, null, null], "externref null")
checkAll(new WebAssembly.Table({ element: "funcref", initial: 3 }),
[null, null, null], "funcref default")
checkAll(new WebAssembly.Table({ element: "funcref", initial: 3 }, null),
[null, null, null], "funcref null")
}
async function testExternrefObjectFill() {
const obj = { tag: "fill" }
const t = new WebAssembly.Table({ element: "externref", initial: 5 }, obj)
checkAll(t, [obj, obj, obj, obj, obj], "externref object")
assert.eq(t.get(0), t.get(4))
const size = 1000
const large = new WebAssembly.Table({ element: "externref", initial: size }, obj)
assert.eq(large.length, size)
assert.eq(large.get(0), obj)
assert.eq(large.get(size - 1), obj)
assert.eq(large.get(size >> 1), obj)
}
async function testFuncrefFillAndCallIndirect() {
const fn = (await instantiate(helperWat, {}, {})).exports.f
const growable = new WebAssembly.Table({ element: "funcref", initial: 4, maximum: 8 }, fn)
for (let i = 0; i < 4; ++i)
assert.eq(growable.get(i), fn)
assert.eq(growable.get(0)(), 42)
const fixed = new WebAssembly.Table({ element: "funcref", initial: 4, maximum: 4 }, fn)
for (let i = 0; i < 4; ++i)
assert.eq(fixed.get(i), fn)
assert.eq(fixed.get(1)(), 42)
const callGrowable = (await instantiate(callIndirectGrowableWat, {
env: { table: growable },
}, {})).exports.call
for (let i = 0; i < 4; ++i)
assert.eq(callGrowable(i), 42)
const callFixed = (await instantiate(callIndirectWat, {
env: { table: fixed },
}, {})).exports.call
for (let i = 0; i < 4; ++i)
assert.eq(callFixed(i), 42)
}
async function testFuncrefFillSurvivesGC() {
const n = 64
let growable
let fixed
let callFixed
let callGrowable
{
const fn = (await instantiate(helperWat, {}, {})).exports.f
growable = new WebAssembly.Table({ element: "funcref", initial: n, maximum: n * 2 }, fn)
fixed = new WebAssembly.Table({ element: "funcref", initial: n, maximum: n }, fn)
callGrowable = (await instantiate(`
(module
(type $sig (func (result i32)))
(import "env" "table" (table ${n} ${n * 2} funcref))
(func (export "call") (param i32) (result i32)
(call_indirect (type $sig) (local.get 0)))
)
`, { env: { table: growable } }, {})).exports.call
callFixed = (await instantiate(`
(module
(type $sig (func (result i32)))
(import "env" "table" (table ${n} ${n} funcref))
(func (export "call") (param i32) (result i32)
(call_indirect (type $sig) (local.get 0)))
)
`, { env: { table: fixed } }, {})).exports.call
}
fullGC()
for (let i = 0; i < n; ++i) {
assert.eq(typeof growable.get(i), "function")
assert.eq(growable.get(i)(), 42)
assert.eq(callGrowable(i), 42)
assert.eq(typeof fixed.get(i), "function")
assert.eq(fixed.get(i)(), 42)
assert.eq(callFixed(i), 42)
}
}
async function testExternrefFillSurvivesGC() {
const n = 100
let table
{
table = new WebAssembly.Table({ element: "externref", initial: n }, { tag: 0xbeef })
}
fullGC()
for (let i = 0; i < n; ++i) {
const v = table.get(i)
assert.eq(typeof v, "object")
assert.eq(v.tag, 0xbeef)
}
}
async function test() {
await testDefaultsAndNull()
await testExternrefObjectFill()
await testFuncrefFillAndCallIndirect()
await testFuncrefFillSurvivesGC()
await testExternrefFillSurvivesGC()
}
await assert.asyncTest(test())