Skip to content

Commit 4c93161

Browse files
authored
[js-api] Add tests for WebAssembly.JSTag (#319)
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.
1 parent c5b968f commit 4c93161

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// META: global=window,dedicatedworker,jsshell,shadowrealm
2+
// META: script=/wasm/jsapi/assertions.js
3+
// META: script=/wasm/jsapi/wasm-module-builder.js
4+
5+
test(() => {
6+
assert_throws_js(TypeError, () => new WebAssembly.Exception(WebAssembly.JSTag, [{}]))
7+
}, "Creating a WebAssembly.Exception with JSTag explicitly is not allowed");
8+
9+
promise_test(async () => {
10+
const builder = new WasmModuleBuilder();
11+
const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r);
12+
13+
const throwRefFn = builder.addImport("module", "throw_ref", kSig_r_r);
14+
const sig_r_v = builder.addType(kSig_r_v);
15+
const kSig_re_v = makeSig([], [kExternRefCode, kExnRefCode]);
16+
const sig_re_v = builder.addType(kSig_re_v);
17+
18+
// Calls throw_ref, catches an exception with 'try_table - catch JSTag', and
19+
// returns it
20+
builder.addFunction("catch_js_tag_and_return", kSig_r_r)
21+
.addBody([
22+
kExprBlock, sig_r_v,
23+
kExprTryTable, sig_r_v, 1,
24+
kCatchNoRef, jsTag, 0,
25+
kExprLocalGet, 0,
26+
kExprCallFunction, throwRefFn,
27+
kExprEnd,
28+
kExprEnd,
29+
])
30+
.exportFunc();
31+
32+
// Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag',
33+
// and returns it
34+
builder.addFunction("catch_ref_js_tag_and_return", kSig_r_r)
35+
.addBody([
36+
kExprBlock, sig_re_v,
37+
kExprTryTable, sig_r_v, 1,
38+
kCatchRef, jsTag, 0,
39+
kExprLocalGet, 0,
40+
kExprCallFunction, throwRefFn,
41+
kExprEnd,
42+
kExprReturn,
43+
kExprEnd,
44+
kExprDrop,
45+
])
46+
.exportFunc();
47+
48+
// Calls throw_ref, catches an exception with 'try_table - catch_ref JSTag',
49+
// and rethrows it (with throw_ref)
50+
builder.addFunction("catch_ref_js_tag_and_throw_ref", kSig_r_r)
51+
.addBody([
52+
kExprBlock, sig_re_v,
53+
kExprTryTable, sig_r_v, 1,
54+
kCatchRef, jsTag, 0,
55+
kExprLocalGet, 0,
56+
kExprCallFunction, throwRefFn,
57+
kExprEnd,
58+
kExprReturn,
59+
kExprEnd,
60+
kExprThrowRef,
61+
])
62+
.exportFunc();
63+
64+
function throw_ref(x) {
65+
throw x;
66+
}
67+
const buffer = builder.toBuffer();
68+
const {instance} = await WebAssembly.instantiate(buffer, {
69+
module: { throw_ref, JSTag: WebAssembly.JSTag }
70+
});
71+
72+
const obj = {};
73+
const wasmTag = new WebAssembly.Tag({parameters:['externref']});
74+
const exn = new WebAssembly.Exception(wasmTag, [obj]);
75+
76+
// Test catch w/ return:
77+
// This throws obj as a JS exception so it should be caught by the program and
78+
// be returned as the original obj.
79+
assert_equals(obj, instance.exports.catch_js_tag_and_return(obj));
80+
// This is a WebAssembly.Exception, so the exception should just pass through
81+
// the program without being caught.
82+
assert_throws_exactly(exn, () => instance.exports.catch_js_tag_and_return(exn));
83+
84+
// Test catch_ref w/ return:
85+
// This throws obj as a JS exception so it should be caught by the program and
86+
// be returned as the original obj.
87+
assert_equals(obj, instance.exports.catch_ref_js_tag_and_return(obj));
88+
// This is a WebAssembly.Exception, so the exception should just pass through
89+
// the program without being caught.
90+
assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_return(exn));
91+
92+
// Test catch_ref w/ throw_ref:
93+
// This throws obj as a JS exception so it should be caught by the program and
94+
// be rethrown.
95+
assert_throws_exactly(obj, () => instance.exports.catch_ref_js_tag_and_throw_ref(obj));
96+
// This is a WebAssembly.Exception, so the exception should just pass through
97+
// the program without being caught.
98+
assert_throws_exactly(exn, () => instance.exports.catch_ref_js_tag_and_throw_ref(exn));
99+
}, "JS tag catching tests");
100+
101+
promise_test(async () => {
102+
const builder = new WasmModuleBuilder();
103+
const jsTag = builder.addImportedTag("module", "JSTag", kSig_v_r);
104+
105+
// Throw a JS object with WebAssembly.JSTag and check that we can catch it
106+
// as-is from JavaScript.
107+
builder.addFunction("throw_js_tag", kSig_v_r)
108+
.addBody([
109+
kExprLocalGet, 0,
110+
kExprThrow, jsTag,
111+
])
112+
.exportFunc();
113+
114+
const buffer = builder.toBuffer();
115+
const {instance} = await WebAssembly.instantiate(buffer, {
116+
module: { JSTag: WebAssembly.JSTag }
117+
});
118+
119+
const obj = {};
120+
assert_throws_exactly(obj, () => instance.exports.throw_js_tag(obj));
121+
}, "JS tag throwing test");

0 commit comments

Comments
 (0)