summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/exnref/try-table.js
diff options
context:
space:
mode:
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.js384
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);
+ }
+ }
+}