print_origin("generate_table_init.js");
function emit_a() {
print(
`
(module
(func (export "ef0") (result i32) (i32.const 0))
(func (export "ef1") (result i32) (i32.const 1))
(func (export "ef2") (result i32) (i32.const 2))
(func (export "ef3") (result i32) (i32.const 3))
(func (export "ef4") (result i32) (i32.const 4))
)
(register "a")`);
}
function emit_b(insn, table) {
print(
`
(module
(type (func (result i32))) ;; type #0
(import "a" "ef0" (func (result i32))) ;; index 0
(import "a" "ef1" (func (result i32)))
(import "a" "ef2" (func (result i32)))
(import "a" "ef3" (func (result i32)))
(import "a" "ef4" (func (result i32))) ;; index 4
(table $t0 30 30 funcref)
(table $t1 30 30 funcref)
(elem (table $t${table}) (i32.const 2) func 3 1 4 1)
(elem funcref
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
(elem (table $t${table}) (i32.const 12) func 7 5 2 3 6)
(elem funcref
(ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
(func (result i32) (i32.const 5)) ;; index 5
(func (result i32) (i32.const 6))
(func (result i32) (i32.const 7))
(func (result i32) (i32.const 8))
(func (result i32) (i32.const 9)) ;; index 9
(func (export "test")
${insn})
(func (export "check") (param i32) (result i32)
(call_indirect $t${table} (type 0) (local.get 0)))
)
`);
}
function tab_test(instruction, table, expected_result_vector) {
emit_b(instruction, table);
print(`(invoke "test")`);
for (let i = 0; i < expected_result_vector.length; i++) {
let expected = expected_result_vector[i];
if (expected === undefined) {
print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`);
} else {
print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`);
}
}
}
emit_a();
let e = undefined;
for ( let table of [0, 1] ) {
tab_test(`(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4))`,
table,
[e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
tab_test(`(table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3))`,
table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);
tab_test(
`(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4))
(elem.drop 1)
(table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3))
(elem.drop 3)
(table.copy $t${table} ${table} (i32.const 20) (i32.const 15) (i32.const 5))
(table.copy $t${table} ${table} (i32.const 21) (i32.const 29) (i32.const 1))
(table.copy $t${table} ${table} (i32.const 24) (i32.const 10) (i32.const 1))
(table.copy $t${table} ${table} (i32.const 13) (i32.const 11) (i32.const 4))
(table.copy $t${table} ${table} (i32.const 19) (i32.const 20) (i32.const 5))`,
table,
[e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);
}
print(
`(assert_invalid
(module
(func (export "test")
(elem.drop 0)))
"unknown elem segment 0")
`);
print(
`(assert_invalid
(module
(func (export "test")
(table.init 0 (i32.const 12) (i32.const 1) (i32.const 1))))
"unknown table 0")
`);
print(
`(assert_invalid
(module
(elem funcref (ref.func 0))
(func (result i32) (i32.const 0))
(func (export "test")
(elem.drop 4)))
"unknown elem segment 4")
`);
print(
`(assert_invalid
(module
(elem funcref (ref.func 0))
(func (result i32) (i32.const 0))
(func (export "test")
(table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
"unknown table 0")
`);
let tab0_len = 30;
let tab1_len = 28;
function do_test(insn1, insn2, table, errText)
{
print(`
(module
(table $t0 ${tab0_len} ${tab0_len} funcref)
(table $t1 ${tab1_len} ${tab1_len} funcref)
(elem (table $t${table}) (i32.const 2) func 3 1 4 1)
(elem funcref
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
(elem (table $t${table}) (i32.const 12) func 7 5 2 3 6)
(elem funcref
(ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
(func (result i32) (i32.const 0))
(func (result i32) (i32.const 1))
(func (result i32) (i32.const 2))
(func (result i32) (i32.const 3))
(func (result i32) (i32.const 4))
(func (result i32) (i32.const 5))
(func (result i32) (i32.const 6))
(func (result i32) (i32.const 7))
(func (result i32) (i32.const 8))
(func (result i32) (i32.const 9))
(func (export "test")
${insn1}
${insn2}))`);
if (errText !== undefined) {
print(`(assert_trap (invoke "test") "${errText}")`);
} else {
print(`(invoke "test")`);
}
}
function tab_test1(insn1, table, errText) {
do_test(insn1, "", table, errText);
}
function tab_test2(insn1, insn2, errText) {
do_test(insn1, insn2, 0, errText);
}
tab_test1("(elem.drop 2)", 0,
undefined);
tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", 0,
"out of bounds table access");
tab_test2(
"(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
"(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))",
undefined);
tab_test2("(elem.drop 1)",
"(elem.drop 1)",
undefined);
tab_test2("(elem.drop 1)",
"(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
"out of bounds table access");
tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", 0,
"out of bounds table access");
tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", 0,
"out of bounds table access");
for ( let [table, oobval] of [[0,30],[1,28]] ) {
tab_test1(`(table.init $t${table} 1 (i32.const ${oobval-2}) (i32.const 1) (i32.const 3))`,
table,
"out of bounds table access");
tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 4) (i32.const 0))`,
table,
undefined);
tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 5) (i32.const 0))`,
table,
"out of bounds table access");
tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 2) (i32.const 0))`,
table,
undefined);
tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 2) (i32.const 0))`,
table,
"out of bounds table access");
tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 4) (i32.const 0))`,
table,
undefined);
tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 5) (i32.const 0))`,
table,
"out of bounds table access");
}
{
const tys = ['i32', 'f32', 'i64', 'f64'];
for (let ty1 of tys) {
for (let ty2 of tys) {
for (let ty3 of tys) {
if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
continue; print(
`
(assert_invalid
(module
(table 10 funcref)
(elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
(func $f0)
(func (export "test")
(table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
"type mismatch")`);
}}}
}
const tbl_init_len = 16;
function tbl_init(min, max, backup, write, segoffs=0) {
print(
`
(module
(type (func (result i32)))
(table ${min} ${max} funcref)
(elem funcref
(ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
(ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
(ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
(ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
(func $f0 (export "f0") (result i32) (i32.const 0))
(func $f1 (export "f1") (result i32) (i32.const 1))
(func $f2 (export "f2") (result i32) (i32.const 2))
(func $f3 (export "f3") (result i32) (i32.const 3))
(func $f4 (export "f4") (result i32) (i32.const 4))
(func $f5 (export "f5") (result i32) (i32.const 5))
(func $f6 (export "f6") (result i32) (i32.const 6))
(func $f7 (export "f7") (result i32) (i32.const 7))
(func $f8 (export "f8") (result i32) (i32.const 8))
(func $f9 (export "f9") (result i32) (i32.const 9))
(func $f10 (export "f10") (result i32) (i32.const 10))
(func $f11 (export "f11") (result i32) (i32.const 11))
(func $f12 (export "f12") (result i32) (i32.const 12))
(func $f13 (export "f13") (result i32) (i32.const 13))
(func $f14 (export "f14") (result i32) (i32.const 14))
(func $f15 (export "f15") (result i32) (i32.const 15))
(func (export "test") (param $n i32) (result i32)
(call_indirect (type 0) (local.get $n)))
(func (export "run") (param $offs i32) (param $len i32)
(table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`);
let offs = min - backup;
print(`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds table access")`);
for (let i=0; i < min; i++) {
print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`);
}
}
tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2), tbl_init_len);
tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2)-1, tbl_init_len);
tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4, tbl_init_len*2);
tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4-1, tbl_init_len*2-1);
tbl_init(tbl_init_len*4, tbl_init_len*4, tbl_init_len, 0xFFFFFFF0);
tbl_init(tbl_init_len, tbl_init_len, tbl_init_len, 0xFFFFFFFC, Math.floor(tbl_init_len/2));
print(
`
(module
(table 1 funcref)
;; 65 elem segments. 64 is the smallest positive number that is encoded
;; differently as a signed LEB.
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref) (elem funcref) (elem funcref) (elem funcref)
(elem funcref)
(func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0))))`)