From 1254b564b2d36cbf96ef8b8fe0c17fa2fa668ae3 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 18 Feb 2021 04:36:56 +0900 Subject: [EH] Make rethrow's target a try label (#3568) I was previously mistaken about `rethrow`'s argument rule and thought it only counted `catch`'s depth. But it turns out it follows the same rule `delegate`'s label: the immediate argument follows the same rule as when computing branch labels, but it only can target `try` labels (semantically it targets that `try`'s corresponding `catch`); otherwise it will be a validation failure. Unlike `delegate`, `rethrow`'s label denotes not where to rethrow, but which exception to rethrow. For example, ```wasm try $l0 catch ($l0) try $l1 catch ($l1) rethrow $l0 ;; rethrow the exception caught by 'catch ($l0)' end end ``` Refer to this comment for the more detailed informal semantics: https://github.com/WebAssembly/exception-handling/issues/146#issuecomment-777714491 --- This also reverts some of `delegateTarget` -> `exceptionTarget` changes done in #3562 in the validator. Label validation rules apply differently for `delegate` and `rethrow` for try-catch. For example, this is valid: ```wasm try $l0 try delegate $l0 catch ($l0) end ``` But this is NOT valid: ```wasm try $l0 catch ($l0) try delegate $l0 end ``` So `try`'s label should be used within try-catch range (not catch-end range) for `delegate`s. But for the `rethrow` the rule is different. For example, this is valid: ```wasm try $l0 catch ($l0) rethrow $l0 end ``` But this is NOT valid: ```wasm try $l0 rethrow $l0 catch ($l0) end ``` So the `try`'s label should be used within catch-end range instead. --- src/ir/branch-utils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ir/branch-utils.h') diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h index 826483b09..f6c55c563 100644 --- a/src/ir/branch-utils.h +++ b/src/ir/branch-utils.h @@ -83,7 +83,7 @@ void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) { } else if (auto* br = expr->dynCast()) { func(name, br->getCastType()); } else { - assert(expr->is()); // delegate + assert(expr->is() || expr->is()); // delegate or rethrow } }); } @@ -135,14 +135,14 @@ inline bool replacePossibleTarget(Expression* branch, Name from, Name to) { return worked; } -// Replace all delegate targets within the given AST. +// Replace all delegate/rethrow targets within the given AST. inline void replaceExceptionTargets(Expression* ast, Name from, Name to) { struct Replacer : public PostWalker> { Name from, to; Replacer(Name from, Name to) : from(from), to(to) {} void visitExpression(Expression* curr) { - if (curr->is()) { + if (curr->is() || curr->is()) { operateOnScopeNameUses(curr, [&](Name& name) { if (name == from) { name = to; -- cgit v1.2.3