diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/exnref/try-table.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/exnref/try-table.js | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/exnref/try-table.js b/js/src/jit-test/tests/wasm/exnref/try-table.js new file mode 100644 index 0000000000..c89330917c --- /dev/null +++ b/js/src/jit-test/tests/wasm/exnref/try-table.js @@ -0,0 +1,384 @@ +// A try_table acts like a block label, with results +{ + let maxResults1 = Array.from(Array(1000).keys()); + let maxResults2 = maxResults1.map((x) => x - 1); + const TESTS = [ + ['i32', 'i32.const', [0], [1]], + ['i32 '.repeat(1000), 'i32.const', maxResults1, maxResults2], + ['i64', 'i64.const', [0], [1]], + ['i64 '.repeat(1000), 'i64.const', maxResults1, maxResults2], + ['f32', 'f32.const', [0], [1]], + ['f32 '.repeat(1000), 'f32.const', maxResults1, maxResults2], + ['f64', 'f64.const', [0], [1]], + ['f64 '.repeat(1000), 'f64.const', maxResults1, maxResults2], + ]; + for (let [types, constructor, values1, values2] of TESTS) { + let {test} = wasmEvalText(`(module + (func (export "test") (param $shouldBranch i32) (result ${types}) + try_table (result ${types}) + ${values2.map((x) => `${constructor} ${x}`).join(" ")} + (br_if 1 local.get $shouldBranch) + ${values1.map((x) => `${constructor} ${x}`).join(" ")} + br 0 + end + ) + )`).exports; + assertEqResults(test(0), values1); + assertEqResults(test(1), values2); + } +} + +// A try_table can have params +{ + let maxParams1 = Array.from(Array(1000).keys()); + const TESTS = [ + ['i32', 'i32.const', [0]], + ['i32 '.repeat(1000), 'i32.const', maxParams1], + ['i64', 'i64.const', [0]], + ['i64 '.repeat(1000), 'i64.const', maxParams1], + ['f32', 'f32.const', [0]], + ['f32 '.repeat(1000), 'f32.const', maxParams1], + ['f64', 'f64.const', [0]], + ['f64 '.repeat(1000), 'f64.const', maxParams1], + ]; + for (let [types, constructor, params] of TESTS) { + let {test} = wasmEvalText(`(module + (func (export "test") (result ${types}) + ${params.map((x) => `${constructor} ${x}`).join(" ")} + try_table (param ${types}) + return + end + unreachable + ) + )`).exports; + assertEqResults(test(), params); + } +} + +// Test try_table catching exceptions +{ + let {test} = wasmEvalText(`(module + (tag $A (param i32)) + (tag $B (param i32)) + (tag $C) + + (table funcref (elem $throwA $throwB $throwC $doNothing)) + + (type $empty (func)) + (func $throwA + i32.const 1 + throw $A + ) + (func $throwB + i32.const 2 + throw $B + ) + (func $throwC + throw $C + ) + (func $doNothing) + + (func (export "test") (param i32) (result i32) + block $handleA (result i32 exnref) + block $handleB (result i32 exnref) + block $handleUnknown (result exnref) + try_table + (catch_ref $A $handleA) + (catch_ref $B $handleB) + (catch_all_ref $handleUnknown) + + (call_indirect (type $empty) + local.get 0) + end + (; nothing threw ;) + i32.const -1 + return + end + (; $handleUnknown ;) + drop + i32.const 3 + return + end + (; $handleB ;) + drop + return + end + (; $handleA ;) + drop + return + ) + )`).exports; + // Throwing A results in 1 from the payload from the catch + assertEq(test(0), 1); + // Throwing B results in 2 from the payload from the catch + assertEq(test(1), 2); + // Throwing C results in 3 from the constant in the catch_all + assertEq(test(2), 3); + // Not throwing anything gets -1 from the fallthrough + assertEq(test(3), -1); +} + +// Test try_table catching exceptions without capturing the exnref +{ + let {test} = wasmEvalText(`(module + (tag $A (param i32)) + (tag $B (param i32)) + (tag $C) + + (table funcref (elem $throwA $throwB $throwC $doNothing)) + + (type $empty (func)) + (func $throwA + i32.const 1 + throw $A + ) + (func $throwB + i32.const 2 + throw $B + ) + (func $throwC + throw $C + ) + (func $doNothing) + + (func (export "test") (param i32) (result i32) + block $handleA (result i32) + block $handleB (result i32) + block $handleUnknown + try_table + (catch $A $handleA) + (catch $B $handleB) + (catch_all $handleUnknown) + + (call_indirect (type $empty) + local.get 0) + end + (; nothing threw ;) + i32.const -1 + return + end + (; $handleUnknown ;) + i32.const 3 + return + end + (; $handleB ;) + return + end + (; $handleA ;) + return + ) + )`).exports; + // Throwing A results in 1 from the payload from the catch + assertEq(test(0), 1); + // Throwing B results in 2 from the payload from the catch + assertEq(test(1), 2); + // Throwing C results in 3 from the constant in the catch_all + assertEq(test(2), 3); + // Not throwing anything gets -1 from the fallthrough + assertEq(test(3), -1); +} + +// Test try_table catching exceptions with various payloads +{ + let maxResults1 = Array.from(Array(999).keys()); + const TESTS = [ + ['i32', 'i32.const', [0]], + ['i32 '.repeat(999), 'i32.const', maxResults1], + ['i64', 'i64.const', [0]], + ['i64 '.repeat(999), 'i64.const', maxResults1], + ['f32', 'f32.const', [0]], + ['f32 '.repeat(999), 'f32.const', maxResults1], + ['f64', 'f64.const', [0]], + ['f64 '.repeat(999), 'f64.const', maxResults1], + ]; + for (let [types, constructor, params] of TESTS) { + let {testCatch, testCatchRef} = wasmEvalText(`(module + (tag $E (param ${types})) + + (func (export "testCatch") (result ${types}) + try_table (catch $E 0) + ${params.map((x) => `${constructor} ${x}`).join(" ")} + throw $E + end + unreachable + ) + (func (export "testCatchRef") (result ${types}) + (block (result ${types} exnref) + try_table (catch_ref $E 0) + ${params.map((x) => `${constructor} ${x}`).join(" ")} + throw $E + end + unreachable + ) + drop + return + ) + + )`).exports; + assertEqResults(testCatch(), params); + assertEqResults(testCatchRef(), params); + } +} + +// Test setting locals in conditional control flow +{ + let {test} = wasmEvalText(`(module + (tag $E) + + (func (export "test") (param $shouldThrow i32) (result i32) + (local $result i32) + + (block $join + (block $catch + try_table (catch $E $catch) + local.get $shouldThrow + if + throw $E + end + (local.set $result i32.const 0) + br $join + end + ) + (local.set $result i32.const 1) + br $join + ) + + local.get $result + ) + + )`).exports; + assertEq(test(0), 0); + assertEq(test(1), 1); +} + +// Matching catch clauses is done in order +{ + let {testCatch, testCatchRef, testCatchAll, testCatchAllRef} = wasmEvalText(`(module + (tag $E) + + (func (export "testCatch") + (block $good + (block $bad + try_table (catch $E $good) (catch $E $bad) (catch_all $bad) + throw $E + end + ) + unreachable + ) + ) + (func (export "testCatchAll") + (block $good + (block $bad + try_table (catch_all $good) (catch $E $bad) (catch $E $bad) + throw $E + end + ) + unreachable + ) + ) + (func (export "testCatchRef") + (block $good (result exnref) + (block $bad (result exnref) + try_table (catch_ref $E $good) (catch_ref $E $bad) (catch_all_ref $bad) + throw $E + end + unreachable + ) + unreachable + ) + drop + ) + (func (export "testCatchAllRef") + (block $good (result exnref) + (block $bad (result exnref) + try_table (catch_all_ref $good) (catch_ref $E $bad) (catch_ref $E $bad) + throw $E + end + unreachable + ) + unreachable + ) + drop + ) + )`).exports; + testCatch(); + testCatchAll(); + testCatchRef(); + testCatchAllRef(); +} + +// Test try_table as target of a delegate +{ + let {test} = wasmEvalText(`(module + (tag $E) + (func (export "test") + block $good + block $bad + try_table $a (catch_all $good) + try + try + throw $E + delegate $a + catch $E + br $bad + end + end + end + unreachable + end + ) + )`).exports; + test(); +} + +// Try table cannot be target of rethrow +{ + wasmFailValidateText(`(module + (func + try_table (catch_all 0) rethrow 0 end + ) + )`, /rethrow target/); +} + +// Test try_table catching and rethrowing JS exceptions +{ + let tag = new WebAssembly.Tag({parameters: []}); + let exn = new WebAssembly.Exception(tag, []); + let values = [...WasmExternrefValues, exn]; + function throwJS(value) { + throw value; + } + let {test} = wasmEvalText(`(module + (import "" "tag" (tag $tag)) + (import "" "throwJS" (func $throwJS (param externref))) + (func $innerRethrow (param externref) + (block (result exnref) + try_table (catch_ref $tag 0) (catch_all_ref 0) + local.get 0 + call $throwJS + end + return + ) + throw_ref + ) + (func (export "test") (param externref) + (block (result exnref) + try_table (catch_ref $tag 0) (catch_all_ref 0) + local.get 0 + call $innerRethrow + end + return + ) + throw_ref + ) + )`, {"": {tag, throwJS}}).exports; + + for (let value of values) { + try { + test(value); + assertEq(true, false); + } catch (thrownValue) { + assertEq(thrownValue, value); + } + } +} |