From 4c77ac53281b3f48fdb1428c3d1cf1d9425614b5 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sat, 29 Jun 2024 01:08:28 +0000 Subject: [PATCH 1/2] [js-api] Add tests for WebAssembly.JSTag This adds tests for `WebAssembly.JSTag`. The tests are adapted from https://github.com/v8/v8/blob/main/test/mjsunit/wasm/exnref-api.js. Confirmed that they run successfully with web test infrastructure in Chrome with `--js-flags=--experimental-wasm-exnref` command line argument. The only thing failing there was the shadowrealm test, which I think we should add a separate expectation files like the existing `***.tentative.any.shadowrealm-expected.txt` in https://github.com/chromium/chromium/tree/main/third_party/blink/web_tests/external/wpt/wasm/jsapi/exception. But given that we don't host these files in this EH repo, I'll just upload the js files. --- test/js-api/exception/jsTag.tentative.any.js | 122 +++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 test/js-api/exception/jsTag.tentative.any.js diff --git a/test/js-api/exception/jsTag.tentative.any.js b/test/js-api/exception/jsTag.tentative.any.js new file mode 100644 index 00000000..ff718cb9 --- /dev/null +++ b/test/js-api/exception/jsTag.tentative.any.js @@ -0,0 +1,122 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/assertions.js +// META: script=/wasm/jsapi/wasm-module-builder.js + +test(() => { + assert_throws_js(TypeError, () => new WebAssembly.Exception(WebAssembly.JSTag, [{}])) +}, "Creating a WebAssembly.Exception with JSTag explicitly is not allowed"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r); + + const throwRefFn = builder.addImport("module", "throw_ref", kSig_r_r); + const sig_r_v = builder.addType(kSig_r_v); + const kSig_re_v = makeSig([], [kExternRefCode, kExnRefCode]); + const sig_re_v = builder.addType(kSig_re_v); + + // Calls throw_ref, catches an exception with 'try_table - catch JSTag', and + // returns it + builder.addFunction("catch_js_tag_and_return", kSig_r_r) + .addBody([ + kExprBlock, sig_r_v, + kExprTryTable, sig_r_v, 1, + kCatchNoRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprEnd, + ]) + .exportFunc(); + + // Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag', + // and returns it + builder.addFunction("catch_ref_js_tag_and_return", kSig_r_r) + .addBody([ + kExprBlock, sig_re_v, + kExprTryTable, sig_r_v, 1, + kCatchRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprReturn, + kExprEnd, + kExprDrop, + ]) + .exportFunc(); + + // Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag', + // and rethrows it (with throw_ref) + builder.addFunction("catch_ref_js_tag_and_throw_ref", kSig_r_r) + .addBody([ + kExprBlock, sig_re_v, + kExprTryTable, sig_r_v, 1, + kCatchRef, jsTag, 0, + kExprLocalGet, 0, + kExprCallFunction, throwRefFn, + kExprEnd, + kExprReturn, + kExprEnd, + kExprThrowRef, + ]) + .exportFunc(); + + function throw_ref(x) { + throw x; + } + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, { + module: { throw_ref, JSTag: WebAssembly.JSTag } + }); + + const obj = {}; + const wasmTag = new WebAssembly.Tag({parameters:['externref']}); + const exn = new WebAssembly.Exception(wasmTag, [obj]); + + // Test catch w/ return: + // This throws obj as a JS exception so it should be caught by the program and + // be returned as the original obj. + assert_equals(obj, instance.exports.catch_js_tag_and_return(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_js_tag_and_return(exn)); + + // Test catch_ref w/ return: + // This throws obj as a JS exception so it should be caught by the program and + // be returned as the original obj. + assert_equals(obj, instance.exports.catch_ref_js_tag_and_return(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_return(exn)); + + // Test catch_ref w/ throw_ref: + // This throws obj as a JS exception so it should be caught by the program and + // be rethrown. + assert_throws_exactly(obj, () => instance.exports.catch_ref_js_tag_and_throw_ref(obj)); + // This is a WebAssembly.Exception, so the exception should just pass through + // the program without being caught. + assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_throw_ref(exn)); +}, "JS tag catching tests"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r); + + // Throw a JS object with WebAssembly.JSTag and check that we can catch it + // as-is from JavaScript. + builder.addFunction("throw_js_tag", kSig_v_r) + .addBody([ + kExprLocalGet, 0, + kExprThrow, jsTag, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + const {instance} = await WebAssembly.instantiate(buffer, { + module: { JSTag: WebAssembly.JSTag } + }); + + const obj = {}; + const wasmTag = new WebAssembly.Tag({parameters:['externref']}); + assert_throws_exactly(obj, () => instance.exports.throw_js_tag(obj)); +}, "JS tag throwing test"); From be90dc75184e05865027036e4769ec363071a5da Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 3 Jul 2024 18:31:04 +0000 Subject: [PATCH 2/2] Remove unused 'wasmTag' --- test/js-api/exception/jsTag.tentative.any.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/js-api/exception/jsTag.tentative.any.js b/test/js-api/exception/jsTag.tentative.any.js index ff718cb9..c5db5537 100644 --- a/test/js-api/exception/jsTag.tentative.any.js +++ b/test/js-api/exception/jsTag.tentative.any.js @@ -117,6 +117,5 @@ promise_test(async () => { }); const obj = {}; - const wasmTag = new WebAssembly.Tag({parameters:['externref']}); assert_throws_exactly(obj, () => instance.exports.throw_js_tag(obj)); }, "JS tag throwing test");