Skip to content
This repository was archived by the owner on Nov 3, 2021. It is now read-only.

Generalize test generators for table.copy and table.init to multi-table #84

Merged
merged 2 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/core/memory_copy.wast
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
;;
;; Generated by ../meta/generate_memory_copy.js
;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE.
;;

(module
Expand Down
1 change: 1 addition & 0 deletions test/core/memory_fill.wast
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
;;
;; Generated by ../meta/generate_memory_fill.js
;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE.
;;

(module
Expand Down
1 change: 1 addition & 0 deletions test/core/memory_init.wast
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
;;
;; Generated by ../meta/generate_memory_init.js
;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE.
;;

(module
Expand Down
2,149 changes: 1,818 additions & 331 deletions test/core/table_copy.wast

Large diffs are not rendered by default.

512 changes: 440 additions & 72 deletions test/core/table_init.wast

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion test/meta/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
SHARED_MEM=false

# SpiderMonkey shell
JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js
JSSHELL=~/mozilla-central/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js

# Node.js
#JSSHELL=./noderun.sh $(SHARED_MEM)
Expand Down
1 change: 1 addition & 0 deletions test/meta/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const PAGESIZE = 65536;
function print_origin(origin) {
print(";;");
print(";; Generated by ../meta/" + origin);
print(";; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE.");
print(";;");
}

Expand Down
250 changes: 146 additions & 104 deletions test/meta/generate_table_copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function emit_a() {
// value 0 to 9 indicating the function called, or will throw an exception if
// the table entry is empty.

function emit_b(insn) {
function emit_b(insn, t0, t1) {
print(
`
(module
Expand All @@ -36,22 +36,27 @@ function emit_b(insn) {
(import "a" "ef2" (func (result i32)))
(import "a" "ef3" (func (result i32)))
(import "a" "ef4" (func (result i32))) ;; index 4
(table 30 30 funcref)
(elem (i32.const 2) 3 1 4 1)
(table $t0 30 30 funcref)
(table $t1 30 30 funcref)
(elem (table $t${t0}) (i32.const 2) func 3 1 4 1)
(elem funcref
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
(elem (i32.const 12) 7 5 2 3 6)
(elem (table $t${t0}) (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))
(elem (table $t${t1}) (i32.const 3) func 1 3 1 4)
(elem (table $t${t1}) (i32.const 11) func 6 3 2 5 7)
(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 (type 0) (local.get 0)))
(func (export "check_t0") (param i32) (result i32)
(call_indirect $t${t0} (type 0) (local.get 0)))
(func (export "check_t1") (param i32) (result i32)
(call_indirect $t${t1} (type 0) (local.get 0)))
)
`);
}
Expand All @@ -60,16 +65,29 @@ function emit_b(insn) {
// given |instruction| to modify the table, and then probes the table by making
// indirect calls, one for each element of |expected_result_vector|. The
// results are compared to those in the vector.
//
// "dest_table" may be t0 or t1.

function tab_test(instruction, expected_result_vector) {
emit_b(instruction);
function tab_test(args, t0, t1, dest_table, expected_t0, expected_t1) {
if (typeof args != "string")
emit_b("(nop)", t0, t1);
else
emit_b(`(table.copy $t${dest_table} $t${t0} ${args})`, t0, t1);
print(`(invoke "test")`);
for (let i = 0; i < expected_result_vector.length; i++) {
let expected = expected_result_vector[i];
for (let i = 0; i < expected_t0.length; i++) {
let expected = expected_t0[i];
if (expected === undefined) {
print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`);
print(`(assert_trap (invoke "check_t0" (i32.const ${i})) "uninitialized element")`);
} else {
print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`);
print(`(assert_return (invoke "check_t0" (i32.const ${i})) (i32.const ${expected}))`);
}
}
for (let i = 0; i < expected_t1.length; i++) {
let expected = expected_t1[i];
if (expected === undefined) {
print(`(assert_trap (invoke "check_t1" (i32.const ${i})) "uninitialized element")`);
} else {
print(`(assert_return (invoke "check_t1" (i32.const ${i})) (i32.const ${expected}))`);
}
}
}
Expand All @@ -80,50 +98,72 @@ emit_a();
// to count through the vector entries when debugging.
let e = undefined;

// This just gives the initial state of the table, with its active
// initialisers applied
tab_test("(nop)",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over non-null
tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over null
tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]);

// Copy null over non-null
tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null over null
tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, non overlapping
tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))",
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]);

// Copy null and non-null entries, overlapping, backwards
tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))",
[e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, overlapping, forwards
tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))",
[e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]);
for ( let table of [0,1] ) {
let other_table = (table + 1) % 2;

// Tests for copying in a single table.

// This just gives the initial state of the table, with its active
// initialisers applied
tab_test(false, table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over non-null
tab_test("(i32.const 13) (i32.const 2) (i32.const 3)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over null
tab_test("(i32.const 25) (i32.const 15) (i32.const 2)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null over non-null
tab_test("(i32.const 13) (i32.const 25) (i32.const 3)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null over null
tab_test("(i32.const 20) (i32.const 22) (i32.const 4)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, non overlapping
tab_test("(i32.const 25) (i32.const 1) (i32.const 3)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, overlapping, backwards
tab_test("(i32.const 10) (i32.const 12) (i32.const 7)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, overlapping, forwards
tab_test("(i32.const 12) (i32.const 10) (i32.const 7)", table, other_table, table,
[e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Tests for copying from one table to the other. Here, overlap and copy
// direction don't matter.

tab_test("(i32.const 10) (i32.const 0) (i32.const 20)", table, other_table, other_table,
[e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e],
[e,e,e,1,3, 1,4,e,e,e, e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e]);
}

// Out-of-bounds checks.

function do_test(insn1, insn2, errText)
{
print(`
(module
(table 30 30 funcref)
(elem (i32.const 2) 3 1 4 1)
(table $t0 30 30 funcref)
(table $t1 30 30 funcref)
(elem (table $t0) (i32.const 2) func 3 1 4 1)
(elem funcref
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
(elem (i32.const 12) 7 5 2 3 6)
(elem (table $t0) (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))
Expand Down Expand Up @@ -156,63 +196,65 @@ function tab_test_nofail(insn1, insn2) {
do_test(insn1, insn2, undefined, undefined);
}

// Here we test the boundary-failure cases. The table's valid indices are 0..29
// inclusive.

// copy: dst range invalid
tab_test2("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))",
"",
"out of bounds");

// copy: dst wraparound end of 32 bit offset space
tab_test2("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))",
"",
"out of bounds");

// copy: src range invalid
tab_test2("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))",
"",
"out of bounds");

// copy: src wraparound end of 32 bit offset space
tab_test2("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))",
"",
"out of bounds");

// copy: zero length with both offsets in-bounds is OK
tab_test_nofail(
"(table.copy (i32.const 15) (i32.const 25) (i32.const 0))",
"");

// copy: zero length with dst offset out of bounds at the end of the table is allowed
tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))",
"",
undefined);

// copy: zero length with dst offset out of bounds past the end of the table is not allowed
tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))",
"",
"out of bounds");

// copy: zero length with src offset out of bounds at the end of the table is allowed
tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
"",
undefined);

// copy: zero length with src offset out of bounds past the end of the table is not allowed
tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))",
"",
"out of bounds");

// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed
tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))",
"",
undefined);

// copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed
tab_test2("(table.copy (i32.const 31) (i32.const 31) (i32.const 0))",
"",
"out of bounds");
for ( let dest of ["$t0","$t1"] ) {
// Here we test the boundary-failure cases. The table's valid indices are 0..29
// inclusive.

// copy: dst range invalid
tab_test2(`(table.copy ${dest} $t0 (i32.const 28) (i32.const 1) (i32.const 3))`,
"",
"out of bounds");

// copy: dst wraparound end of 32 bit offset space
tab_test2(`(table.copy ${dest} $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))`,
"",
"out of bounds");

// copy: src range invalid
tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 6))`,
"",
"out of bounds");

// copy: src wraparound end of 32 bit offset space
tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))`,
"",
"out of bounds");

// copy: zero length with both offsets in-bounds is OK
tab_test_nofail(
`(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 0))`,
"");

// copy: zero length with dst offset out of bounds at the end of the table is allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 15) (i32.const 0))`,
"",
undefined);

// copy: zero length with dst offset out of bounds past the end of the table is not allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 15) (i32.const 0))`,
"",
"out of bounds");

// copy: zero length with src offset out of bounds at the end of the table is allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 30) (i32.const 0))`,
"",
undefined);

// copy: zero length with src offset out of bounds past the end of the table is not allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 31) (i32.const 0))`,
"",
"out of bounds");

// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 30) (i32.const 0))`,
"",
undefined);

// copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed
tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 31) (i32.const 0))`,
"",
"out of bounds");
}

// table.copy: out of bounds of the table for the source or target, but should
// perform the operation up to the appropriate bound. Major cases:
Expand Down
Loading