-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[js-api] Re-add old tests to test/js-api/exception
These two tests used to be in https://github.com/WebAssembly/exception-handling/tree/main/test/js-api/exception and were moved into https://github.com/WebAssembly/exception-handling/tree/main/test/legacy/exceptions/js-api in #305. I'm planning new version of these tests that use `try_table` and `throw_ref` in https://github.com/WebAssembly/exception-handling/tree/main/test/js-api/exception, but it wouldn't require to rewrite the whole tests, but copying these tests into the this directory and modify them in a single PR makes Github think these are brand-new files, resulting in a large diff containing the whole files that is difficult to review (and which has been reviewed and in the repo for a long time already). So I'm making a PR that only re-adds these file here so that I can add changes to these files in another PR.
- Loading branch information
Showing
2 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); |