| (module | |
| (tag $e-v) | |
| (tag $e-i32 (param i32)) | |
| (tag $e-f32 (param f32)) | |
| (tag $e-i32-f32 (param i32 f32)) | |
| (func $throw_single_value (export "throw_single_value") | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (func (export "throw_multiple_values") | |
| (throw $e-i32-f32 (i32.const 3) (f32.const 3.5)) | |
| ) | |
| (func (export "try_nothrow") (result i32) | |
| (try (result i32) | |
| (do | |
| (i32.const 3) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (i32.const 0) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_throw_catch") (result i32) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_throw_nocatch") (result i32) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-f32 | |
| (drop (pop f32)) | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_throw_catchall") (result i32) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-f32 | |
| (drop (pop f32)) | |
| (i32.const 4) | |
| ) | |
| (catch_all | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_call_catch") (result i32) | |
| (try (result i32) | |
| (do | |
| (call $throw_single_value) | |
| (unreachable) | |
| ) | |
| (catch $e-i32 | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_throw_multivalue_catch") (result i32) (local $x (tuple i32 f32)) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32-f32 (i32.const 5) (f32.const 1.5)) | |
| ) | |
| (catch $e-i32-f32 | |
| (local.set $x | |
| (pop (tuple i32 f32)) | |
| ) | |
| (tuple.extract 2 0 | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_throw_rethrow") | |
| (try $l0 | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (rethrow $l0) | |
| ) | |
| ) | |
| ) | |
| (func (export "try_call_rethrow") | |
| (try $l0 | |
| (do | |
| (call $throw_single_value) | |
| ) | |
| (catch_all | |
| (rethrow $l0) | |
| ) | |
| ) | |
| ) | |
| (func (export "rethrow_target_test1") (result i32) | |
| (try (result i32) | |
| (do | |
| (try | |
| (do | |
| (throw $e-i32 (i32.const 1)) | |
| ) | |
| (catch_all | |
| (try $l0 | |
| (do | |
| (throw $e-i32 (i32.const 2)) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (rethrow $l0) ;; rethrow (i32.const 2) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (catch $e-i32 | |
| (pop i32) ;; result is (i32.const 2) | |
| ) | |
| ) | |
| ) | |
| ;; Can we handle rethrows with the depth > 0? | |
| (func (export "rethrow_target_test2") (result i32) | |
| (try (result i32) | |
| (do | |
| (try $l0 | |
| (do | |
| (throw $e-i32 (i32.const 1)) | |
| ) | |
| (catch_all | |
| (try | |
| (do | |
| (throw $e-i32 (i32.const 2)) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (rethrow 1) ;; rethrow (i32.const 1) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (catch $e-i32 | |
| (pop i32) ;; result is (i32.const 1) | |
| ) | |
| ) | |
| ) | |
| ;; Tests whether the exception stack is managed correctly after rethrows | |
| (func (export "rethrow_target_test3") (result i32) | |
| (try (result i32) | |
| (do | |
| (try $l0 | |
| (do | |
| (try $l1 | |
| (do | |
| (throw $e-i32 (i32.const 1)) | |
| ) | |
| (catch_all | |
| (try | |
| (do | |
| (throw $e-i32 (i32.const 2)) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (rethrow $l1) ;; rethrow (i32.const 1) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (catch $e-i32 | |
| (drop (pop i32)) | |
| (rethrow $l0) ;; rethrow (i32.const 1) again | |
| ) | |
| ) | |
| ) | |
| (catch $e-i32 | |
| (pop i32) ;; result is (i32.const 1) | |
| ) | |
| ) | |
| ) | |
| (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_exception (invoke "throw_single_value")) | |
| (assert_exception (invoke "throw_multiple_values")) | |
| (assert_return (invoke "try_nothrow") (i32.const 3)) | |
| (assert_return (invoke "try_throw_catch") (i32.const 3)) | |
| (assert_exception (invoke "try_throw_nocatch")) | |
| (assert_return (invoke "try_throw_catchall") (i32.const 3)) | |
| (assert_return (invoke "try_call_catch") (i32.const 5)) | |
| (assert_return (invoke "try_throw_multivalue_catch") (i32.const 5)) | |
| (assert_exception (invoke "try_throw_rethrow")) | |
| (assert_exception (invoke "try_call_rethrow")) | |
| (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_exception (invoke "try_delegate_to_catchless_try")) | |
| (assert_return (invoke "try_delegate_to_delegate") (i32.const 3)) | |
| (assert_exception (invoke "try_delegate_to_caller")) | |
| (assert_invalid | |
| (module | |
| (func $f0 | |
| (try | |
| (do (nop)) | |
| (catch $e-i32 | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "try's body type must match catch's body type" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do (i32.const 0)) | |
| (catch $e-i32 | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "try's type does not match try body's type" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (throw $e-i32 (f32.const 0)) | |
| ) | |
| ) | |
| "tag param types must match" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32 f32)) | |
| (func $f0 | |
| (throw $e-i32 (f32.const 0)) | |
| ) | |
| ) | |
| "tag's param numbers must match" | |
| ) | |
| (module | |
| (func $f0 | |
| (block $l0 | |
| (try | |
| (do | |
| (try | |
| (do) | |
| (delegate $l0) ;; target is a block | |
| ) | |
| ) | |
| (catch_all) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (module | |
| (func $f0 | |
| (try $l0 | |
| (do) | |
| (catch_all | |
| (try | |
| (do) | |
| (delegate $l0) ;; the target catch is above the delegate | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (assert_invalid | |
| (module | |
| (func $f0 | |
| (block $l0 | |
| (try | |
| (do) | |
| (catch_all | |
| (rethrow $l0) ;; target is a block | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "all rethrow targets must be valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (func $f0 | |
| (try $l0 | |
| (do | |
| (rethrow $l0) ;; Not within the target try's catch | |
| ) | |
| (catch_all) | |
| ) | |
| ) | |
| ) | |
| "all rethrow targets must be valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e) | |
| ) | |
| ) | |
| ) | |
| "catch's tag name is invalid: e" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-none (param)) | |
| (func $f0 (result i32) | |
| (try (result i32) | |
| (do | |
| (i32.const 0) | |
| ) | |
| (catch $e-none | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's tag (e-none) doesn't have any params, but there are pops" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32) | |
| ) | |
| ) | |
| ) | |
| "catch's tag (e-i32) has params, so there should be a single pop within the catch body" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32 | |
| (drop | |
| (pop i32) | |
| ) | |
| (drop | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's tag (e-i32) has params, so there should be a single pop within the catch body" | |
| ) | |
| (assert_invalid | |
| (module | |
| (func $f0 (result i32) | |
| (try (result i32) | |
| (do | |
| (i32.const 0) | |
| ) | |
| (catch_all | |
| (pop i32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch_all's body should not have pops" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 (result f32) | |
| (try (result f32) | |
| (do | |
| (f32.const 0) | |
| ) | |
| (catch $e-i32 | |
| (pop f32) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's tag (e-i32)'s pop doesn't have the same type as the tag's params" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 (result i32) | |
| (try (result i32) | |
| (do | |
| (i32.const 0) | |
| ) | |
| (catch $e-i32 | |
| (drop | |
| (i32.const 0) | |
| ) | |
| (pop i32) ;; Not the first children within 'catch' | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's body (e-i32)'s pop's location is not valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32 | |
| (throw $e-i32 | |
| (block (result i32) | |
| (pop i32) ;; pop is within a block | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's body (e-i32)'s pop's location is not valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32 | |
| (throw $e-i32 | |
| (loop (result i32) | |
| (pop i32) ;; pop is within a loop | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's body (e-i32)'s pop's location is not valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32 | |
| (throw $e-i32 | |
| (try (result i32) | |
| (do | |
| (pop i32) ;; pop is within a try | |
| ) | |
| (catch_all | |
| (i32.const 0) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's body (e-i32)'s pop's location is not valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (func $f0 | |
| (try | |
| (do) | |
| (catch $e-i32 | |
| (throw $e-i32 | |
| (if (result i32) | |
| (i32.const 0) | |
| (then | |
| (pop i32) ;; pop is within an if true body | |
| ) | |
| (else | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's body (e-i32)'s pop's location is not valid" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32) (result i32)) | |
| (tag $e-f32 (param f32)) | |
| (func (export "try_throw_nocatch") (result i32) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-f32 | |
| (drop (pop f32)) | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "tags with result types must not be used for exception handling" | |
| ) | |
| (assert_invalid | |
| (module | |
| (tag $e-i32 (param i32)) | |
| (tag $e-f32 (param f32) (result i32)) | |
| (func (export "try_throw_nocatch") (result i32) | |
| (try (result i32) | |
| (do | |
| (throw $e-i32 (i32.const 5)) | |
| ) | |
| (catch $e-f32 | |
| (drop (pop f32)) | |
| (i32.const 3) | |
| ) | |
| ) | |
| ) | |
| ) | |
| "catch's tag (e-f32) has result values, which is not allowed for exception handling" | |
| ) |