Skip to content

Commit

Permalink
[js-api] Update basic and identity tests for exnref (#316)
Browse files Browse the repository at this point in the history
This updates `basic.tentative.any.js` and `identity.tentative.any.js`
tests to use the new instructions (`try_table` and `throw_ref`). In
addition to converting existing tests to use the new instruction while
maintaining the semantics, I added a new test in
`basic.tentative.any.js` that makes use of all four `catch` clause
variants to show all catch clauses works well in JS API tests.

These new tests reauire `--js-flags=--experimental-wasm-exnref` argument
to chrome, which is not currently supported in WPT out of the box. I've
instead confirmed these run with chrome web tests infrastructure
(https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_tests.md#Running-Web-Tests).
  • Loading branch information
aheejin authored Jul 4, 2024
1 parent 5837755 commit c5b968f
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 53 deletions.
90 changes: 76 additions & 14 deletions test/js-api/exception/basic.tentative.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ function assert_throws_wasm(fn, message) {
promise_test(async () => {
const kSig_v_r = makeSig([kWasmExternRef], []);
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_r);
const tagIndexExternref = builder.addTag(kSig_v_r);
builder.addFunction("throw_param", kSig_v_r)
.addBody([
kExprLocalGet, 0,
kExprThrow, tagIndex,
kExprThrow, tagIndexExternref,
])
.exportFunc();
const buffer = builder.toBuffer();
Expand All @@ -44,11 +44,11 @@ promise_test(async () => {

promise_test(async () => {
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_a);
const tagIndexAnyref = builder.addTag(kSig_v_a);
builder.addFunction("throw_null", kSig_v_v)
.addBody([
kExprRefNull, kAnyFuncCode,
kExprThrow, tagIndex,
kExprThrow, tagIndexAnyref,
])
.exportFunc();
const buffer = builder.toBuffer();
Expand All @@ -58,11 +58,11 @@ promise_test(async () => {

promise_test(async () => {
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_i);
const tagIndexI32 = builder.addTag(kSig_v_i);
builder.addFunction("throw_int", kSig_v_v)
.addBody([
...wasmI32Const(7),
kExprThrow, tagIndex,
kExprThrow, tagIndexI32,
])
.exportFunc();
const buffer = builder.toBuffer();
Expand All @@ -73,12 +73,18 @@ promise_test(async () => {
promise_test(async () => {
const builder = new WasmModuleBuilder();
const fnIndex = builder.addImport("module", "fn", kSig_v_v);
const tagIndex= builder.addTag(kSig_v_r);
const tagIndexExternref = builder.addTag(kSig_v_r);

builder.addFunction("catch_exception", kSig_r_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, fnIndex,
kExprCatch, tagIndex,
kExprBlock, kWasmVoid,
kExprBlock, kExternRefCode,
kExprTryTable, kWasmVoid, 1,
kCatchNoRef, tagIndexExternref, 0,
kExprCallFunction, fnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprReturn,
kExprEnd,
kExprRefNull, kExternRefCode,
Expand All @@ -100,10 +106,15 @@ promise_test(async () => {
const fnIndex = builder.addImport("module", "fn", kSig_v_v);
builder.addFunction("catch_and_rethrow", kSig_r_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, fnIndex,
kExprCatchAll,
kExprRethrow, 0x00,
kExprBlock, kWasmVoid,
kExprBlock, kExnRefCode,
kExprTryTable, kWasmVoid, 1,
kCatchAllRef, 0,
kExprCallFunction, fnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrowRef,
kExprEnd,
kExprRefNull, kExternRefCode,
])
Expand All @@ -118,3 +129,54 @@ promise_test(async () => {
});
assert_throws_exactly(error, () => instance.exports.catch_and_rethrow());
}, "Imported JS function throws, Wasm catches and rethrows");

promise_test(async () => {
const builder = new WasmModuleBuilder();
const fnIndex = builder.addImport("module", "fn", kSig_v_v);
const tagI32 = new WebAssembly.Tag({ parameters: ["i32"] });
const tagIndexI32 = builder.addImportedTag("module", "tagI32", kSig_v_i);
const exn = new WebAssembly.Exception(tagI32, [42]);
const kSig_ie_v = makeSig([], [kWasmI32, kExnRefCode]);
const sig_ie_v = builder.addType(kSig_ie_v);

builder.addFunction("all_catch_clauses", kSig_i_v)
.addBody([
kExprBlock, kWasmVoid,
kExprBlock, kExnRefCode,
kExprBlock, sig_ie_v,
kExprBlock, kWasmVoid,
kExprBlock, kWasmI32,
kExprTryTable, kWasmVoid, 4,
kCatchNoRef, tagIndexI32, 0,
kCatchAllNoRef, 1,
kCatchRef, tagIndexI32, 2,
kCatchAllRef, 3,
kExprCallFunction, fnIndex,
kExprEnd,
kExprBr, 4,
kExprEnd,
kExprReturn,
kExprEnd,
kExprBr, 2,
kExprEnd,
kExprDrop,
kExprDrop,
kExprBr, 1,
kExprEnd,
kExprDrop,
kExprEnd,
kExprI32Const, 0,
])
.exportFunc();

const buffer = builder.toBuffer();

const fn = () => {
throw exn;
};
const {instance} = await WebAssembly.instantiate(buffer, {
module: { fn, tagI32: tagI32 }
});
const result = instance.exports.all_catch_clauses();
assert_equals(result, 42);
}, "try-table uses all four kinds of catch clauses, one of which catches an exception");
107 changes: 69 additions & 38 deletions test/js-api/exception/identity.tentative.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ test(() => {
let wasmTagExnSamePayload = null;
let wasmTagExnDiffPayload = null;

const kSig_ie_v = makeSig([], [kWasmI32, kExnRefCode]);
const sig_ie_v = builder.addType(kSig_ie_v);

const imports = {
module: {
throwJSTagExn: function() { throw jsTagExn; },
Expand All @@ -31,55 +34,73 @@ test(() => {
};

// Call a JS function that throws an exception using a JS-defined tag, catches
// it with a 'catch' instruction, and rethrows it.
// it with a 'catch_ref' instruction, and rethrows it.
builder
.addFunction("catch_js_tag_rethrow", kSig_v_v)
.addFunction("catch_ref_js_tag_throw_ref", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwJSTagExnIndex,
kExprCatch, jsTagIndex,
kExprDrop,
kExprRethrow, 0x00,
kExprBlock, kWasmVoid,
kExprBlock, sig_ie_v,
kExprTryTable, kWasmVoid, 1,
kCatchRef, jsTagIndex, 0,
kExprCallFunction, throwJSTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrowRef,
kExprEnd
])
.exportFunc();

// Call a JS function that throws an exception using a Wasm-defined tag,
// catches it with a 'catch' instruction, and rethrows it.
// catches it with a 'catch_ref' instruction, and rethrows it.
builder
.addFunction("catch_wasm_tag_rethrow", kSig_v_v)
.addFunction("catch_ref_wasm_tag_throw_ref", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwWasmTagExnIndex,
kExprCatch, wasmTagIndex,
kExprDrop,
kExprRethrow, 0x00,
kExprBlock, kWasmVoid,
kExprBlock, sig_ie_v,
kExprTryTable, kWasmVoid, 1,
kCatchRef, wasmTagIndex, 0,
kExprCallFunction, throwWasmTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrowRef,
kExprEnd
])
.exportFunc();

// Call a JS function that throws an exception using a JS-defined tag, catches
// it with a 'catch_all' instruction, and rethrows it.
// it with a 'catch_all_ref' instruction, and rethrows it.
builder
.addFunction("catch_all_js_tag_rethrow", kSig_v_v)
.addFunction("catch_all_ref_js_tag_throw_ref", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwJSTagExnIndex,
kExprCatchAll,
kExprRethrow, 0x00,
kExprBlock, kWasmVoid,
kExprBlock, kExnRefCode,
kExprTryTable, kWasmVoid, 1,
kCatchAllRef, 0,
kExprCallFunction, throwJSTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrowRef,
kExprEnd
])
.exportFunc();

// Call a JS function that throws an exception using a Wasm-defined tag,
// catches it with a 'catch_all' instruction, and rethrows it.
// catches it with a 'catch_all_ref' instruction, and rethrows it.
builder
.addFunction("catch_all_wasm_tag_rethrow", kSig_v_v)
.addFunction("catch_all_ref_wasm_tag_throw_ref", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwWasmTagExnIndex,
kExprCatchAll,
kExprRethrow, 0x00,
kExprBlock, kWasmVoid,
kExprBlock, kExnRefCode,
kExprTryTable, kWasmVoid, 1,
kCatchAllRef, 0,
kExprCallFunction, throwWasmTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrowRef,
kExprEnd
])
.exportFunc();
Expand All @@ -89,12 +110,17 @@ test(() => {
builder
.addFunction("catch_js_tag_return_payload", kSig_i_v)
.addBody([
kExprTry, kWasmI32,
kExprCallFunction, throwJSTagExnIndex,
kExprI32Const, 0x00,
kExprCatch, jsTagIndex,
kExprBlock, kWasmVoid,
kExprBlock, kWasmI32,
kExprTryTable, kWasmVoid, 1,
kCatchNoRef, jsTagIndex, 0,
kExprCallFunction, throwJSTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprReturn,
kExprEnd
kExprEnd,
kExprI32Const, 0
])
.exportFunc();

Expand All @@ -103,9 +129,14 @@ test(() => {
builder
.addFunction("catch_js_tag_throw_payload", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwJSTagExnIndex,
kExprCatch, jsTagIndex,
kExprBlock, kWasmVoid,
kExprBlock, kWasmI32,
kExprTryTable, kWasmVoid, 1,
kCatchNoRef, jsTagIndex, 0,
kExprCallFunction, throwJSTagExnIndex,
kExprEnd,
kExprBr, 1,
kExprEnd,
kExprThrow, jsTagIndex,
kExprEnd
])
Expand All @@ -117,7 +148,7 @@ test(() => {
// The exception object's identity should be preserved across 'rethrow's in
// Wasm code. Do tests with a tag defined in JS.
try {
result.instance.exports.catch_js_tag_rethrow();
result.instance.exports.catch_ref_js_tag_throw_ref();
} catch (e) {
assert_equals(e, jsTagExn);
// Even if they have the same payload, they are different objects, so they
Expand All @@ -126,7 +157,7 @@ test(() => {
assert_not_equals(e, jsTagExnDiffPayload);
}
try {
result.instance.exports.catch_all_js_tag_rethrow();
result.instance.exports.catch_all_ref_js_tag_throw_ref();
} catch (e) {
assert_equals(e, jsTagExn);
assert_not_equals(e, jsTagExnSamePayload);
Expand All @@ -139,14 +170,14 @@ test(() => {
wasmTagExnSamePayload = new WebAssembly.Exception(wasmTag, [42]);
wasmTagExnDiffPayload = new WebAssembly.Exception(wasmTag, [53]);
try {
result.instance.exports.catch_wasm_tag_rethrow();
result.instance.exports.catch_ref_wasm_tag_throw_ref();
} catch (e) {
assert_equals(e, wasmTagExn);
assert_not_equals(e, wasmTagExnSamePayload);
assert_not_equals(e, wasmTagExnDiffPayload);
}
try {
result.instance.exports.catch_all_wasm_tag_rethrow();
result.instance.exports.catch_all_ref_wasm_tag_throw_ref();
} catch (e) {
assert_equals(e, wasmTagExn);
assert_not_equals(e, wasmTagExnSamePayload);
Expand Down
2 changes: 1 addition & 1 deletion test/legacy/exceptions/js-api/basic.tentative.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ promise_test(async () => {
promise_test(async () => {
const builder = new WasmModuleBuilder();
const fnIndex = builder.addImport("module", "fn", kSig_v_v);
const tagIndex= builder.addTag(kSig_v_r);
const tagIndex = builder.addTag(kSig_v_r);
builder.addFunction("catch_exception", kSig_r_v)
.addBody([
kExprTry, kWasmVoid,
Expand Down

0 comments on commit c5b968f

Please sign in to comment.