From e2f49d8227f2b71e4dede5cf4074bb9f65e3d77f Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 13 Aug 2019 00:29:26 +0900 Subject: Add basic exception handling support (#2282) This adds basic support for exception handling instructions, according to the spec: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md This PR includes support for: - Binary reading/writing - Wast reading/writing - Stack IR - Validation - binaryen.js + C API - Few IR routines: branch-utils, type-updating, etc - Few passes: just enough to make `wasm-opt -O` pass - Tests This PR does not include support for many optimization passes, fuzzer, or interpreter. They will be follow-up PRs. Try-catch construct is modeled in Binaryen IR in a similar manner to that of if-else: each of try body and catch body will contain a block, which can be omitted if there is only a single instruction. This block will not be emitted in wast or binary, as in if-else. As in if-else, `class Try` contains two expressions each for try body and catch body, and `catch` is not modeled as an instruction. `exnref` value pushed by `catch` is get by `pop` instruction. `br_on_exn` is special: it returns different types of values when taken and not taken. We make `exnref`, the type `br_on_exn` pushes if not taken, as `br_on_exn`'s type. --- test/spec/exception-handling.wast | 123 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 test/spec/exception-handling.wast (limited to 'test/spec/exception-handling.wast') diff --git a/test/spec/exception-handling.wast b/test/spec/exception-handling.wast new file mode 100644 index 000000000..d81bd433c --- /dev/null +++ b/test/spec/exception-handling.wast @@ -0,0 +1,123 @@ +(module + (event $e0 (attr 0) (param i32)) + (event $e1 (attr 0) (param i32 f32)) + + (func $exnref_test (param $0 exnref) (result exnref) + (local.get $0) + ) + + (func $eh_test (local $exn exnref) + (try + (throw $e0 (i32.const 0)) + (catch + ;; Multi-value is not available yet, so block can't take a value from + ;; stack. So this uses locals for now. + (local.set $exn (exnref.pop)) + (drop + (block $l0 (result i32) + (rethrow + (br_on_exn $l0 $e0 (local.get $exn)) + ) + ) + ) + ) + ) + ) +) + +(assert_invalid + (module + (func $f0 + (try + (nop) + (catch (i32.const 0)) + ) + ) + ) + "try's body type must match catch's body type" +) + +(assert_invalid + (module + (func $f0 + (try + (i32.const 0) + (catch (i32.const 0)) + ) + ) + ) + "try's type does not match try body's type" +) + +(assert_invalid + (module + (event $e0 (attr 0) (param i32)) + (func $f0 + (throw $e0 (f32.const 0)) + ) + ) + "event param types must match" +) + +(assert_invalid + (module + (event $e0 (attr 0) (param i32 f32)) + (func $f0 + (throw $e0 (f32.const 0)) + ) + ) + "event's param numbers must match" +) + +(assert_invalid + (module + (func $f0 + (rethrow (i32.const 0)) + ) + ) + "rethrow's argument must be exnref type" +) + +(assert_invalid + (module + (event $e0 (attr 0) (param i32)) + (func $f0 (result i32) + (block $l0 (result i32) + (drop + (br_on_exn $l0 $e0 (i32.const 0)) + ) + (i32.const 0) + ) + ) + ) + "br_on_exn's argument must be unreachable or exnref type" +) + +(assert_invalid + (module + (event $e0 (attr 0) (param i32)) + (func $f0 (result i32) (local $0 exnref) + (block $l0 (result i32) + (i32.eqz + (br_on_exn $l0 $e0 (local.get $0)) + ) + ) + ) + ) + "i32.eqz input must be i32" +) + +(assert_invalid + (module + (event $e0 (attr 0) (param i32)) + (func $f0 (result f32) (local $0 exnref) + (block $l0 (result f32) + (drop + (br_on_exn $l0 $e0 (local.get $0)) + ) + (f32.const 0) + ) + ) + ) + "block+breaks must have right type if breaks return a value" +) -- cgit v1.2.3