diff options
-rw-r--r-- | src/wasm-interpreter.h | 16 | ||||
-rw-r--r-- | test/spec/exception-handling.wast | 86 |
2 files changed, 102 insertions, 0 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index caccef654..ecfc00d93 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2697,6 +2697,9 @@ private: FunctionScope& scope; // Stack of <caught exception, caught catch's try label> SmallVector<std::pair<WasmException, Name>, 4> exceptionStack; + // The current delegate target, if delegation of an exception is in + // progress. If no delegation is in progress, this will be an empty Name. + Name currDelegateTarget; protected: // Returns the instance that defines the memory used by this one. @@ -3443,6 +3446,16 @@ private: try { return this->visit(curr->body); } catch (const WasmException& e) { + // If delegation is in progress and the current try is not the target of + // the delegation, don't handle it and just rethrow. + if (currDelegateTarget.is()) { + if (currDelegateTarget == curr->name) { + currDelegateTarget.clear(); + } else { + throw; + } + } + auto processCatchBody = [&](Expression* catchBody) { // Push the current exception onto the exceptionStack in case // 'rethrow's use it @@ -3469,6 +3482,9 @@ private: if (curr->hasCatchAll()) { return processCatchBody(curr->catchBodies.back()); } + if (curr->isDelegate()) { + currDelegateTarget = curr->delegateTarget; + } // This exception is not caught by this try-catch. Rethrow it. throw; } diff --git a/test/spec/exception-handling.wast b/test/spec/exception-handling.wast index 33454f1f9..4b817a81d 100644 --- a/test/spec/exception-handling.wast +++ b/test/spec/exception-handling.wast @@ -201,6 +201,88 @@ ) ) ) + + (func (export "try_delegate_caught") (result i32) + (try $l0 (result i32) + (do + (try (result i32) + (do + (try (result i32) + (do + (throw $e-i32 (i32.const 3)) + ) + (delegate $l0) + ) + ) + (catch_all + (i32.const 0) + ) + ) + ) + (catch $e-i32 + (pop i32) + ) + ) + ) + + (func (export "try_delegate_to_catchless_try") (result i32) + (try $l0 (result i32) + (do + (try (result i32) + (do + (try (result i32) + (do + (throw $e-i32 (i32.const 3)) + ) + (delegate $l0) + ) + ) + (catch_all + (i32.const 0) + ) + ) + ) + ) + ) + + (func (export "try_delegate_to_delegate") (result i32) + (try $l0 (result i32) + (do + (try $l1 (result i32) + (do + (try (result i32) + (do + (throw $e-i32 (i32.const 3)) + ) + (delegate $l1) + ) + ) + (delegate $l0) + ) + ) + (catch $e-i32 + (pop i32) + ) + ) + ) + + (func (export "try_delegate_to_caller") + (try $l0 + (do + (try $l1 + (do + (try + (do + (throw $e-i32 (i32.const 3)) + ) + (delegate 2) ;; to caller + ) + ) + ) + ) + (catch_all) + ) + ) ) (assert_trap (invoke "throw_single_value")) @@ -216,6 +298,10 @@ (assert_return (invoke "rethrow_target_test1") (i32.const 2)) (assert_return (invoke "rethrow_target_test2") (i32.const 1)) (assert_return (invoke "rethrow_target_test3") (i32.const 1)) +(assert_return (invoke "try_delegate_caught") (i32.const 3)) +(assert_trap (invoke "try_delegate_to_catchless_try")) +(assert_return (invoke "try_delegate_to_delegate") (i32.const 3)) +(assert_trap (invoke "try_delegate_to_caller")) (assert_invalid (module |