Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js-api] Re-add old tests to test/js-api/exception #315

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions test/js-api/exception/basic.tentative.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// META: global=window,dedicatedworker,jsshell,shadowrealm
// META: script=/wasm/jsapi/wasm-module-builder.js

function assert_throws_wasm(fn, message) {
try {
fn();
assert_not_reached(`expected to throw with ${message}`);
} catch (e) {
assert_true(e instanceof WebAssembly.Exception, `Error should be a WebAssembly.Exception with ${message}`);
}
}

promise_test(async () => {
const kSig_v_r = makeSig([kWasmExternRef], []);
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_r);
builder.addFunction("throw_param", kSig_v_r)
.addBody([
kExprLocalGet, 0,
kExprThrow, tagIndex,
])
.exportFunc();
const buffer = builder.toBuffer();
const {instance} = await WebAssembly.instantiate(buffer, {});
const values = [
undefined,
null,
true,
false,
"test",
Symbol(),
0,
1,
4.2,
NaN,
Infinity,
{},
() => {},
];
for (const v of values) {
assert_throws_wasm(() => instance.exports.throw_param(v), String(v));
}
}, "Wasm function throws argument");

promise_test(async () => {
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_a);
builder.addFunction("throw_null", kSig_v_v)
.addBody([
kExprRefNull, kAnyFuncCode,
kExprThrow, tagIndex,
])
.exportFunc();
const buffer = builder.toBuffer();
const {instance} = await WebAssembly.instantiate(buffer, {});
assert_throws_wasm(() => instance.exports.throw_null());
}, "Wasm function throws null");

promise_test(async () => {
const builder = new WasmModuleBuilder();
const tagIndex = builder.addTag(kSig_v_i);
builder.addFunction("throw_int", kSig_v_v)
.addBody([
...wasmI32Const(7),
kExprThrow, tagIndex,
])
.exportFunc();
const buffer = builder.toBuffer();
const {instance} = await WebAssembly.instantiate(buffer, {});
assert_throws_wasm(() => instance.exports.throw_int());
}, "Wasm function throws integer");

promise_test(async () => {
const builder = new WasmModuleBuilder();
const fnIndex = builder.addImport("module", "fn", kSig_v_v);
const tagIndex= builder.addTag(kSig_v_r);
builder.addFunction("catch_exception", kSig_r_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, fnIndex,
kExprCatch, tagIndex,
kExprReturn,
kExprEnd,
kExprRefNull, kExternRefCode,
])
.exportFunc();

const buffer = builder.toBuffer();

const error = new Error();
const fn = () => { throw error };
const {instance} = await WebAssembly.instantiate(buffer, {
module: { fn }
});
assert_throws_exactly(error, () => instance.exports.catch_exception());
}, "Imported JS function throws");

promise_test(async () => {
const builder = new WasmModuleBuilder();
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,
kExprEnd,
kExprRefNull, kExternRefCode,
])
.exportFunc();

const buffer = builder.toBuffer();

const error = new Error();
const fn = () => { throw error };
const {instance} = await WebAssembly.instantiate(buffer, {
module: { fn }
});
assert_throws_exactly(error, () => instance.exports.catch_and_rethrow());
}, "Imported JS function throws, Wasm catches and rethrows");
170 changes: 170 additions & 0 deletions test/js-api/exception/identity.tentative.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// META: global=window,dedicatedworker,jsshell,shadowrealm
// META: script=/wasm/jsapi/assertions.js
// META: script=/wasm/jsapi/wasm-module-builder.js

test(() => {
const builder = new WasmModuleBuilder();

// Tag defined in JavaScript and imported into Wasm
const jsTag = new WebAssembly.Tag({ parameters: ["i32"] });
const jsTagIndex = builder.addImportedTag("module", "jsTag", kSig_v_i);
const jsTagExn = new WebAssembly.Exception(jsTag, [42]);
const jsTagExnSamePayload = new WebAssembly.Exception(jsTag, [42]);
const jsTagExnDiffPayload = new WebAssembly.Exception(jsTag, [53]);
const throwJSTagExnIndex = builder.addImport("module", "throwJSTagExn", kSig_v_v);

// Tag defined in Wasm and exported to JS
const wasmTagIndex = builder.addTag(kSig_v_i);
builder.addExportOfKind("wasmTag", kExternalTag, wasmTagIndex);
const throwWasmTagExnIndex = builder.addImport("module", "throwWasmTagExn", kSig_v_v);
// Will be assigned after an instance is created
let wasmTagExn = null;
let wasmTagExnSamePayload = null;
let wasmTagExnDiffPayload = null;

const imports = {
module: {
throwJSTagExn: function() { throw jsTagExn; },
throwWasmTagExn: function() { throw wasmTagExn; },
jsTag: jsTag
}
};

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

// Call a JS function that throws an exception using a Wasm-defined tag,
// catches it with a 'catch' instruction, and rethrows it.
builder
.addFunction("catch_wasm_tag_rethrow", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwWasmTagExnIndex,
kExprCatch, wasmTagIndex,
kExprDrop,
kExprRethrow, 0x00,
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.
builder
.addFunction("catch_all_js_tag_rethrow", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwJSTagExnIndex,
kExprCatchAll,
kExprRethrow, 0x00,
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.
builder
.addFunction("catch_all_wasm_tag_rethrow", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwWasmTagExnIndex,
kExprCatchAll,
kExprRethrow, 0x00,
kExprEnd
])
.exportFunc();

// Call a JS function that throws an exception, catches it with a 'catch'
// instruction, and returns its i32 payload.
builder
.addFunction("catch_js_tag_return_payload", kSig_i_v)
.addBody([
kExprTry, kWasmI32,
kExprCallFunction, throwJSTagExnIndex,
kExprI32Const, 0x00,
kExprCatch, jsTagIndex,
kExprReturn,
kExprEnd
])
.exportFunc();

// Call a JS function that throws an exception, catches it with a 'catch'
// instruction, and throws a new exception using that payload.
builder
.addFunction("catch_js_tag_throw_payload", kSig_v_v)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, throwJSTagExnIndex,
kExprCatch, jsTagIndex,
kExprThrow, jsTagIndex,
kExprEnd
])
.exportFunc();

const buffer = builder.toBuffer();

WebAssembly.instantiate(buffer, imports).then(result => {
// 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();
} catch (e) {
assert_equals(e, jsTagExn);
// Even if they have the same payload, they are different objects, so they
// shouldn't compare equal.
assert_not_equals(e, jsTagExnSamePayload);
assert_not_equals(e, jsTagExnDiffPayload);
}
try {
result.instance.exports.catch_all_js_tag_rethrow();
} catch (e) {
assert_equals(e, jsTagExn);
assert_not_equals(e, jsTagExnSamePayload);
assert_not_equals(e, jsTagExnDiffPayload);
}

// Do the same tests with a tag defined in Wasm.
const wasmTag = result.instance.exports.wasmTag;
wasmTagExn = new WebAssembly.Exception(wasmTag, [42]);
wasmTagExnSamePayload = new WebAssembly.Exception(wasmTag, [42]);
wasmTagExnDiffPayload = new WebAssembly.Exception(wasmTag, [53]);
try {
result.instance.exports.catch_wasm_tag_rethrow();
} 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();
} catch (e) {
assert_equals(e, wasmTagExn);
assert_not_equals(e, wasmTagExnSamePayload);
assert_not_equals(e, wasmTagExnDiffPayload);
}

// This function catches the exception and returns its i32 payload, which
// should match the original payload.
assert_equals(result.instance.exports.catch_js_tag_return_payload(), 42);

// This function catches the exception and throws a new exception using the
// its payload. Even if the payload is reused, the exception objects should
// not compare equal.
try {
result.instance.exports.catch_js_tag_throw_payload();
} catch (e) {
assert_equals(e.getArg(jsTag, 0), 42);
assert_not_equals(e, jsTagExn);
}
});
}, "Identity check");
Loading