Add WebAssembly Exception handling tests from spec repo.
diff --git a/wasm/jsapi/exception/constructor.tentative.any.js b/wasm/jsapi/exception/constructor.tentative.any.js
new file mode 100644
index 0000000..0fd47b4
--- /dev/null
+++ b/wasm/jsapi/exception/constructor.tentative.any.js
@@ -0,0 +1,62 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+test(() => {
+  assert_function_name(
+    WebAssembly.Exception,
+    "Exception",
+    "WebAssembly.Exception"
+  );
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Exception, 1, "WebAssembly.Exception");
+}, "length");
+
+test(() => {
+  assert_throws_js(TypeError, () => new WebAssembly.Exception());
+}, "No arguments");
+
+test(() => {
+  const argument = new WebAssembly.Tag({ parameters: [] });
+  assert_throws_js(TypeError, () => WebAssembly.Exception(argument));
+}, "Calling");
+
+test(() => {
+  const invalidArguments = [
+    undefined,
+    null,
+    false,
+    true,
+    "",
+    "test",
+    Symbol(),
+    1,
+    NaN,
+    {},
+  ];
+  for (const invalidArgument of invalidArguments) {
+    assert_throws_js(
+      TypeError,
+      () => new WebAssembly.Exception(invalidArgument),
+      `new Exception(${format_value(invalidArgument)})`
+    );
+  }
+}, "Invalid descriptor argument");
+
+test(() => {
+  const typesAndArgs = [
+    ["i32", 123n],
+    ["i32", Symbol()],
+    ["f32", 123n],
+    ["f64", 123n],
+    ["i64", undefined],
+  ];
+  for (const typeAndArg of typesAndArgs) {
+    const exn = new WebAssembly.Tag({ parameters: [typeAndArg[0]] });
+    assert_throws_js(
+      TypeError,
+      () => new WebAssembly.Exception(exn, typeAndArg[1])
+    );
+  }
+}, "Invalid exception argument");
diff --git a/wasm/jsapi/exception/getArg.tentative.any.js b/wasm/jsapi/exception/getArg.tentative.any.js
new file mode 100644
index 0000000..4b72c61
--- /dev/null
+++ b/wasm/jsapi/exception/getArg.tentative.any.js
@@ -0,0 +1,54 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/memory/assertions.js
+
+test(() => {
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  assert_throws_js(TypeError, () => exn.getArg());
+  assert_throws_js(TypeError, () => exn.getArg(tag));
+}, "Missing arguments");
+
+test(() => {
+  const invalidValues = [undefined, null, true, "", Symbol(), 1, {}];
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  for (argument of invalidValues) {
+    assert_throws_js(TypeError, () => exn.getArg(argument, 0));
+  }
+}, "Invalid exception argument");
+
+test(() => {
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  assert_throws_js(RangeError, () => exn.getArg(tag, 1));
+}, "Index out of bounds");
+
+test(() => {
+  const outOfRangeValues = [
+    undefined,
+    NaN,
+    Infinity,
+    -Infinity,
+    -1,
+    0x100000000,
+    0x1000000000,
+    "0x100000000",
+    {
+      valueOf() {
+        return 0x100000000;
+      },
+    },
+  ];
+
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  for (const value of outOfRangeValues) {
+    assert_throws_js(TypeError, () => exn.getArg(tag, value));
+  }
+}, "Getting out-of-range argument");
+
+test(() => {
+  const tag = new WebAssembly.Tag({ parameters: ["i32"] });
+  const exn = new WebAssembly.Exception(tag, [42]);
+  assert_equals(exn.getArg(tag, 0), 42);
+}, "getArg");
diff --git a/wasm/jsapi/exception/is.tentative.any.js b/wasm/jsapi/exception/is.tentative.any.js
new file mode 100644
index 0000000..e28a88a
--- /dev/null
+++ b/wasm/jsapi/exception/is.tentative.any.js
@@ -0,0 +1,25 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/memory/assertions.js
+
+test(() => {
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  assert_throws_js(TypeError, () => exn.is());
+}, "Missing arguments");
+
+test(() => {
+  const invalidValues = [undefined, null, true, "", Symbol(), 1, {}];
+  const tag = new WebAssembly.Tag({ parameters: [] });
+  const exn = new WebAssembly.Exception(tag, []);
+  for (argument of invalidValues) {
+    assert_throws_js(TypeError, () => exn.is(argument));
+  }
+}, "Invalid exception argument");
+
+test(() => {
+  const tag1 = new WebAssembly.Tag({ parameters: ["i32"] });
+  const tag2 = new WebAssembly.Tag({ parameters: ["i32"] });
+  const exn = new WebAssembly.Exception(tag1, [42]);
+  assert_true(exn.is(tag1));
+  assert_false(exn.is(tag2));
+}, "is");
diff --git a/wasm/jsapi/exception/toString.tentative.any.js b/wasm/jsapi/exception/toString.tentative.any.js
new file mode 100644
index 0000000..5263518
--- /dev/null
+++ b/wasm/jsapi/exception/toString.tentative.any.js
@@ -0,0 +1,21 @@
+// META: global=window,dedicatedworker,jsshell
+
+test(() => {
+  const argument = { parameters: [] };
+  const tag = new WebAssembly.Tag(argument);
+  const exception = new WebAssembly.Exception(tag, []);
+  assert_class_string(exception, "WebAssembly.Exception");
+}, "Object.prototype.toString on an Exception");
+
+test(() => {
+  assert_own_property(WebAssembly.Exception.prototype, Symbol.toStringTag);
+
+  const propDesc = Object.getOwnPropertyDescriptor(
+    WebAssembly.Exception.prototype,
+    Symbol.toStringTag
+  );
+  assert_equals(propDesc.value, "WebAssembly.Exception", "value");
+  assert_equals(propDesc.configurable, true, "configurable");
+  assert_equals(propDesc.enumerable, false, "enumerable");
+  assert_equals(propDesc.writable, false, "writable");
+}, "@@toStringTag exists on the prototype with the appropriate descriptor");
diff --git a/wasm/jsapi/exception/type.tentative.any.js b/wasm/jsapi/exception/type.tentative.any.js
new file mode 100644
index 0000000..dcacfea
--- /dev/null
+++ b/wasm/jsapi/exception/type.tentative.any.js
@@ -0,0 +1,21 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+function assert_type(argument) {
+  const exception = new WebAssembly.Exception(argument);
+  const exceptiontype = exception.type();
+
+  assert_array_equals(exceptiontype.parameters, argument.parameters);
+}
+
+test(() => {
+  assert_type({ "parameters": [] });
+}, "[]");
+
+test(() => {
+  assert_type({ "parameters": ["i32", "i64"] });
+}, "[i32 i64]");
+
+test(() => {
+  assert_type({ "parameters": ["i32", "i64", "f32", "f64"] });
+}, "[i32 i64 f32 f64]");
diff --git a/wasm/jsapi/tag/constructor.tentative.any.js b/wasm/jsapi/tag/constructor.tentative.any.js
new file mode 100644
index 0000000..de63e7b
--- /dev/null
+++ b/wasm/jsapi/tag/constructor.tentative.any.js
@@ -0,0 +1,49 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+test(() => {
+  assert_function_name(WebAssembly.Tag, "Tag", "WebAssembly.Tag");
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Tag, 1, "WebAssembly.Tag");
+}, "length");
+
+test(() => {
+  assert_throws_js(TypeError, () => new WebAssembly.Tag());
+}, "No arguments");
+
+test(() => {
+  const argument = { parameters: [] };
+  assert_throws_js(TypeError, () => WebAssembly.Tag(argument));
+}, "Calling");
+
+test(() => {
+  const invalidArguments = [
+    undefined,
+    null,
+    false,
+    true,
+    "",
+    "test",
+    Symbol(),
+    1,
+    NaN,
+    {},
+  ];
+  for (const invalidArgument of invalidArguments) {
+    assert_throws_js(
+      TypeError,
+      () => new WebAssembly.Tag(invalidArgument),
+      `new Tag(${format_value(invalidArgument)})`
+    );
+  }
+}, "Invalid descriptor argument");
+
+test(() => {
+  const invalidTypes = ["i16", "i128", "f16", "f128", "u32", "u64", "i32\0"];
+  for (const value of invalidTypes) {
+    const argument = { parameters: [value] };
+    assert_throws_js(TypeError, () => new WebAssembly.Tag(argument));
+  }
+}, "Invalid type parameter");
diff --git a/wasm/jsapi/tag/toString.tentative.any.js b/wasm/jsapi/tag/toString.tentative.any.js
new file mode 100644
index 0000000..ad9a4ba
--- /dev/null
+++ b/wasm/jsapi/tag/toString.tentative.any.js
@@ -0,0 +1,20 @@
+// META: global=window,dedicatedworker,jsshell
+
+test(() => {
+  const argument = { parameters: [] };
+  const tag = new WebAssembly.Tag(argument);
+  assert_class_string(tag, "WebAssembly.Tag");
+}, "Object.prototype.toString on a Tag");
+
+test(() => {
+  assert_own_property(WebAssembly.Tag.prototype, Symbol.toStringTag);
+
+  const propDesc = Object.getOwnPropertyDescriptor(
+    WebAssembly.Tag.prototype,
+    Symbol.toStringTag
+  );
+  assert_equals(propDesc.value, "WebAssembly.Tag", "value");
+  assert_equals(propDesc.configurable, true, "configurable");
+  assert_equals(propDesc.enumerable, false, "enumerable");
+  assert_equals(propDesc.writable, false, "writable");
+}, "@@toStringTag exists on the prototype with the appropriate descriptor");
diff --git a/wasm/jsapi/tag/type.tentative.any.js b/wasm/jsapi/tag/type.tentative.any.js
new file mode 100644
index 0000000..9d2f0de
--- /dev/null
+++ b/wasm/jsapi/tag/type.tentative.any.js
@@ -0,0 +1,21 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+function assert_type(argument) {
+  const tag = new WebAssembly.Tag(argument);
+  const tagtype = tag.type();
+
+  assert_array_equals(tagtype.parameters, argument.parameters);
+}
+
+test(() => {
+  assert_type({ parameters: [] });
+}, "[]");
+
+test(() => {
+  assert_type({ parameters: ["i32", "i64"] });
+}, "[i32 i64]");
+
+test(() => {
+  assert_type({ parameters: ["i32", "i64", "f32", "f64"] });
+}, "[i32 i64 f32 f64]");