summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/exceptions/js-api.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/wasm/exceptions/js-api.js')
-rw-r--r--js/src/jit-test/tests/wasm/exceptions/js-api.js490
1 files changed, 490 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/exceptions/js-api.js b/js/src/jit-test/tests/wasm/exceptions/js-api.js
new file mode 100644
index 0000000000..4c2f018808
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/exceptions/js-api.js
@@ -0,0 +1,490 @@
+// Tests for wasm exception proposal JS API features.
+
+load(libdir + "eqArrayHelper.js");
+
+// WebAssembly.Tag tests.
+assertErrorMessage(
+ () => WebAssembly.Tag(),
+ TypeError,
+ /calling a builtin Tag constructor without new is forbidden/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Tag(),
+ TypeError,
+ /At least 1 argument required/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Tag(3),
+ TypeError,
+ /first argument must be a tag descriptor/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Tag({ parameters: ["foobar"] }),
+ TypeError,
+ /bad value type/
+);
+
+new WebAssembly.Tag({ parameters: [] });
+new WebAssembly.Tag({ parameters: ["i32"] });
+new WebAssembly.Tag({ parameters: ["i32", "externref"] });
+
+wasmEvalText(`(module (import "m" "e" (tag)))`, {
+ m: { e: new WebAssembly.Tag({ parameters: [] }) },
+});
+
+wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, {
+ m: { e: new WebAssembly.Tag({ parameters: ["i32"] }) },
+});
+
+wasmEvalText(`(module (import "m" "e" (tag (param i32 i64))))`, {
+ m: { e: new WebAssembly.Tag({ parameters: ["i32", "i64"] }) },
+});
+
+assertErrorMessage(
+ () =>
+ wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, {
+ m: { e: new WebAssembly.Tag({ parameters: [] }) },
+ }),
+ WebAssembly.LinkError,
+ /imported tag 'm.e' signature mismatch/
+);
+
+assertErrorMessage(
+ () =>
+ wasmEvalText(`(module (import "m" "e" (tag (param))))`, {
+ m: { e: new WebAssembly.Tag({ parameters: ["i32"] }) },
+ }),
+ WebAssembly.LinkError,
+ /imported tag 'm.e' signature mismatch/
+);
+
+// Test WebAssembly.Tag methods.
+// TODO: add runtime detection for js-types
+// {
+// let params = [
+// [],
+// ["i32"],
+// ["i32", "i64"],
+// ["f32", "externref"],
+// ["i32", "i64", "f32", "f64"],
+// ];
+
+// for (const arg of params) {
+// const tag = new WebAssembly.Tag({ parameters: arg });
+// assertEqArray(tag.type().parameters, arg);
+// }
+// }
+
+// WebAssembly.Exception tests.
+assertErrorMessage(
+ () => WebAssembly.Exception(),
+ TypeError,
+ /calling a builtin Exception constructor without new is forbidden/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(),
+ TypeError,
+ /At least 2 arguments required/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(3, []),
+ TypeError,
+ /first argument must be a WebAssembly.Tag/
+);
+
+const { tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9 } = wasmEvalText(
+ `(module
+ (tag (export "tag1") (param))
+ (tag (export "tag2") (param i32))
+ (tag (export "tag3") (param i32 f32))
+ (tag (export "tag4") (param i32 externref i32))
+ (tag (export "tag5") (param i32 externref i32 externref))
+ (tag (export "tag6") (param funcref))
+ (tag (export "tag7") (param i64))
+ (tag (export "tag8") (param i32 f64))
+ (tag (export "tag9") (param externref funcref)))`
+).exports;
+
+new WebAssembly.Exception(tag1, []);
+new WebAssembly.Exception(tag2, [3]);
+new WebAssembly.Exception(tag3, [3, 5.5]);
+new WebAssembly.Exception(tag4, [3, "foo", 4]);
+new WebAssembly.Exception(tag5, [3, "foo", 4, "bar"]);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag2, []),
+ TypeError,
+ /expected 1 values but got 0/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag2, [3n]),
+ TypeError,
+ /can't convert BigInt to number/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag6, [undefined]),
+ TypeError,
+ /can only pass WebAssembly exported functions to funcref/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag7, [undefined]),
+ TypeError,
+ /can't convert undefined to BigInt/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag7, {}),
+ TypeError,
+ /\({}\) is not iterable/
+);
+
+assertErrorMessage(
+ () => new WebAssembly.Exception(tag7, 1),
+ TypeError,
+ /second argument must be an object/
+);
+
+// Test Exception methods.
+{
+ const exn1 = new WebAssembly.Exception(tag1, []);
+ assertEq(exn1.is(tag1), true);
+ assertEq(exn1.is(tag2), false);
+ assertErrorMessage(
+ () => exn1.is(),
+ TypeError,
+ /At least 1 argument required/
+ );
+ assertErrorMessage(
+ () => exn1.is(5),
+ TypeError,
+ /first argument must be a WebAssembly.Tag/
+ );
+
+ const exn2 = new WebAssembly.Exception(tag2, [3]);
+ assertEq(exn2.getArg(tag2, 0), 3);
+
+ assertEq(new WebAssembly.Exception(tag2, [undefined]).getArg(tag2, 0), 0);
+
+ const exn4 = new WebAssembly.Exception(tag4, [3, "foo", 4]);
+ assertEq(exn4.getArg(tag4, 0), 3);
+ assertEq(exn4.getArg(tag4, 1), "foo");
+ assertEq(exn4.getArg(tag4, 2), 4);
+
+ const exn5 = new WebAssembly.Exception(tag5, [3, "foo", 4, "bar"]);
+ assertEq(exn5.getArg(tag5, 3), "bar");
+
+ const { funcref } = wasmEvalText(
+ `(module (func (export "funcref")))`
+ ).exports;
+ const exn9 = new WebAssembly.Exception(tag9, ["foo", funcref]);
+ assertEq(exn9.getArg(tag9, 0), "foo");
+ assertEq(exn9.getArg(tag9, 1), funcref);
+
+ assertErrorMessage(
+ () => exn2.getArg(),
+ TypeError,
+ /At least 2 arguments required/
+ );
+ assertErrorMessage(
+ () => exn2.getArg(5, 0),
+ TypeError,
+ /first argument must be a WebAssembly.Tag/
+ );
+ assertErrorMessage(
+ () => exn2.getArg(tag2, "foo"),
+ TypeError,
+ /bad Exception getArg index/
+ );
+ assertErrorMessage(
+ () => exn2.getArg(tag2, 10),
+ RangeError,
+ /bad Exception getArg index/
+ );
+}
+
+// Test throwing a JS constructed exception to Wasm.
+assertEq(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32)
+ try (result i32)
+ call $f
+ (i32.const 0)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag2,
+ f: () => {
+ throw new WebAssembly.Exception(tag2, [42]);
+ },
+ },
+ }
+ ).exports.f(),
+ 42
+);
+
+assertEqArray(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 f32)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32 f32)
+ try (result i32 f32)
+ call $f
+ (i32.const 0)
+ (f32.const 0)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag3,
+ f: () => {
+ throw new WebAssembly.Exception(tag3, [42, 5.5]);
+ },
+ },
+ }
+ ).exports.f(),
+ [42, 5.5]
+);
+
+assertEqArray(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 f64)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32 f64)
+ try (result i32 f64)
+ call $f
+ (i32.const 0)
+ (f64.const 0)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag8,
+ f: () => {
+ throw new WebAssembly.Exception(tag8, [9999, 9999]);
+ },
+ },
+ }
+ ).exports.f(),
+ [9999, 9999]
+);
+
+assertEqArray(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 externref i32)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32 externref i32)
+ try (result i32 externref i32)
+ call $f
+ (i32.const 0)
+ (ref.null extern)
+ (i32.const 0)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag4,
+ f: () => {
+ throw new WebAssembly.Exception(tag4, [42, "foo", 42]);
+ },
+ },
+ }
+ ).exports.f(),
+ [42, "foo", 42]
+);
+
+assertEqArray(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 externref i32 externref)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32 externref i32 externref)
+ try (result i32 externref i32 externref)
+ call $f
+ (i32.const 0)
+ (ref.null extern)
+ (i32.const 0)
+ (ref.null extern)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag5,
+ f: () => {
+ throw new WebAssembly.Exception(tag5, [42, "foo", 42, "bar"]);
+ },
+ },
+ }
+ ).exports.f(),
+ [42, "foo", 42, "bar"]
+);
+
+{
+ const { funcref } = wasmEvalText(
+ `(module (func (export "funcref")))`
+ ).exports;
+ assertEqArray(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param externref funcref)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result externref funcref)
+ try (result externref funcref)
+ call $f
+ (ref.null extern)
+ (ref.null func)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn: tag9,
+ f: () => {
+ throw new WebAssembly.Exception(tag9, ["foo", funcref]);
+ },
+ },
+ }
+ ).exports.f(),
+ ["foo", funcref]
+ );
+}
+
+assertEq(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32)
+ try (result i32)
+ call $f
+ (i32.const 0)
+ catch $exn
+ (i32.const 0)
+ catch_all
+ (i32.const 1)
+ end))`,
+ {
+ m: {
+ exn: tag1,
+ f: () => {
+ throw new WebAssembly.Exception(tag2, [42]);
+ },
+ },
+ }
+ ).exports.f(),
+ 1
+);
+
+{
+ const exn = new WebAssembly.Tag({ parameters: ["i32"] });
+ assertEq(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32)
+ try (result i32)
+ call $f
+ (i32.const 0)
+ catch $exn
+ end))`,
+ {
+ m: {
+ exn,
+ f: () => {
+ throw new WebAssembly.Exception(exn, [42]);
+ },
+ },
+ }
+ ).exports.f(),
+ 42
+ );
+}
+
+{
+ const exn1 = new WebAssembly.Tag({ parameters: ["i32"] });
+ const exn2 = new WebAssembly.Tag({ parameters: ["i32"] });
+ assertEq(
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32)))
+ (import "m" "f" (func $f))
+ (func (export "f") (result i32)
+ try (result i32)
+ call $f
+ (i32.const 0)
+ catch $exn
+ catch_all
+ (i32.const 1)
+ end))`,
+ {
+ m: {
+ exn: exn1,
+ f: () => {
+ throw new WebAssembly.Exception(exn2, [42]);
+ },
+ },
+ }
+ ).exports.f(),
+ 1
+ );
+}
+
+// Test `getArg` on a Wasm-thrown exception.
+assertEq(
+ (() => {
+ try {
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 f64)))
+ (func (export "f")
+ (i32.const 9999)
+ (f64.const 9999)
+ throw $exn))`,
+ { m: { exn: tag8 } }
+ ).exports.f();
+ } catch (exn) {
+ return exn.getArg(tag8, 1);
+ }
+ })(),
+ 9999
+);
+
+assertEqArray(
+ (() => {
+ try {
+ wasmEvalText(
+ `(module
+ (import "m" "exn" (tag $exn (param i32 externref i32 externref)))
+ (func (export "f") (param externref externref)
+ (i32.const 1)
+ (local.get 0)
+ (i32.const 2)
+ (local.get 1)
+ throw $exn))`,
+ { m: { exn: tag5 } }
+ ).exports.f("foo", "bar");
+ } catch (exn) {
+ return [
+ exn.getArg(tag5, 0),
+ exn.getArg(tag5, 1),
+ exn.getArg(tag5, 2),
+ exn.getArg(tag5, 3),
+ ];
+ }
+ })(),
+ [1, "foo", 2, "bar"]
+);