[wasm][eh] Update delegate behavior

Update the behavior of 'delegate' according to:
https://github.com/WebAssembly/exception-handling/issues/176

Summary: delegate can target any block, which just rethrows to the next
outer try/catch.

R=clemensb@chromium.org

Bug: v8:8091
Change-Id: I967db9ab1cbb1a15b2c5e0a1a20f64fa19a3f769
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3140603
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76677}
This commit is contained in:
Thibaud Michaud 2021-09-03 14:15:42 +02:00 committed by V8 LUCI CQ
parent f7d65d5069
commit 7c67bc1928
3 changed files with 54 additions and 22 deletions

View File

@ -2635,19 +2635,15 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 0;
}
// +1 because the current try block is not included in the count.
Control* target = control_at(imm.depth + 1);
if (imm.depth + 1 < control_depth() - 1 && !target->is_try()) {
this->DecodeError(
"delegate target must be a try block or the function block");
return 0;
}
if (target->is_try_catch() || target->is_try_catchall()) {
this->DecodeError(
"cannot delegate inside the catch handler of the target");
return 0;
uint32_t target_depth = imm.depth + 1;
while (target_depth < control_depth() - 1 &&
(!control_at(target_depth)->is_try() ||
control_at(target_depth)->is_try_catch() ||
control_at(target_depth)->is_try_catchall())) {
target_depth++;
}
FallThrough();
CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Delegate, imm.depth + 1, c);
CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(Delegate, target_depth, c);
current_catch_ = c->previous_catch;
EndControl();
PopControl();

View File

@ -1073,3 +1073,41 @@ d8.file.execute("test/mjsunit/wasm/exceptions-utils.js");
assertDoesNotThrow(() => instance.exports.catchless_try(0));
assertWasmThrows(instance, except, [], () => instance.exports.catchless_try(1));
})();
// Delegate to a regular block inside a try block.
(function TestDelegateToBlock() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let except = builder.addTag(kSig_v_v);
builder.addFunction('test', kSig_i_v)
.addBody([
kExprTry, kWasmI32,
kExprBlock, kWasmI32,
kExprTry, kWasmI32,
kExprThrow, except,
kExprDelegate, 0,
kExprEnd,
kExprCatch, except,
kExprI32Const, 2,
kExprEnd,
]).exportFunc();
instance = builder.instantiate();
assertEquals(2, instance.exports.test());
})();
// Delegate to a regular block with no outer try (delegate to caller).
(function TestDelegateToCallerWithBlock() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let except = builder.addTag(kSig_v_v);
builder.addFunction('test', kSig_v_v)
.addBody([
kExprBlock, kWasmVoid,
kExprTry, kWasmVoid,
kExprThrow, except,
kExprDelegate, 0,
kExprEnd
]).exportFunc();
instance = builder.instantiate();
assertThrows(() => instance.exports.test(), WebAssembly.Exception);
})();

View File

@ -2990,18 +2990,16 @@ TEST_F(FunctionBodyDecoderTest, TryDelegate) {
sigs.v_v(),
{WASM_BLOCK(WASM_TRY_OP, WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 2),
kExprCatch, ex, kExprEnd)});
ExpectValidates(sigs.v_v(),
{WASM_TRY_OP, kExprCatch, ex,
WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 0), kExprEnd},
kAppendEnd);
ExpectValidates(sigs.v_v(),
{WASM_TRY_OP,
WASM_BLOCK(WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 0)),
kExprCatch, ex, kExprEnd},
kAppendEnd);
ExpectFailure(sigs.v_v(),
{WASM_TRY_OP,
WASM_BLOCK(WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 0)),
kExprCatch, ex, kExprEnd},
kAppendEnd,
"delegate target must be a try block or the function block");
ExpectFailure(sigs.v_v(),
{WASM_TRY_OP, kExprCatch, ex,
WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 0), kExprEnd},
kAppendEnd,
"cannot delegate inside the catch handler of the target");
ExpectFailure(
sigs.v_v(),
{WASM_BLOCK(WASM_TRY_OP, WASM_TRY_DELEGATE(WASM_STMTS(kExprThrow, ex), 3),