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/example/c-api-kitchen-sink.c | 57 ++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) (limited to 'test/example/c-api-kitchen-sink.c') diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index 8b2d3ae8d..661d04ce2 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -206,6 +206,51 @@ void test_core() { temp13 = makeInt32(module, 10), temp14 = makeInt32(module, 11), temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111); + // Events + BinaryenType eparams[1] = {BinaryenTypeInt32()}; + BinaryenFunctionTypeRef vi = + BinaryenAddFunctionType(module, "vi", BinaryenTypeNone(), eparams, 1); + BinaryenAddEvent(module, "a-event", 0, vi); + + // Exception handling + + // (try + // (throw $a-event (i32.const 0)) + // (catch + // ;; We don't support multi-value yet. Use locals instead. + // (local.set 0 (exnref.pop)) + // (drop + // (block $try-block (result i32) + // (rethrow + // (br_on_exn $try-block $a-event (local.get 5)) + // ) + // ) + // ) + // ) + // ) + BinaryenExpressionRef tryBody = BinaryenThrow( + module, "a-event", (BinaryenExpressionRef[]){makeInt32(module, 0)}, 1); + BinaryenExpressionRef catchBody = BinaryenBlock( + module, + NULL, + (BinaryenExpressionRef[]){ + BinaryenLocalSet(module, 5, BinaryenPop(module, BinaryenTypeExnref())), + BinaryenDrop( + module, + BinaryenBlock(module, + "try-block", + (BinaryenExpressionRef[]){BinaryenRethrow( + module, + BinaryenBrOnExn( + module, + "try-block", + "a-event", + BinaryenLocalGet(module, 5, BinaryenTypeExnref())))}, + 1, + BinaryenTypeInt32()))}, + 2, + BinaryenTypeNone()); + BinaryenExpressionRef valueList[] = { // Unary makeUnary(module, BinaryenClzInt32(), 1), @@ -472,6 +517,8 @@ void test_core() { module, "kitchen()sinker", callOperands4, 4, BinaryenTypeInt32()), BinaryenReturnCallIndirect( module, makeInt32(module, 2449), callOperands4b, 4, "iiIfF"), + // Exception handling + BinaryenTry(module, tryBody, catchBody), // TODO: Host BinaryenNop(module), @@ -488,19 +535,15 @@ void test_core() { BinaryenExpressionRef body = BinaryenBlock(module, "the-body", bodyList, 2, -1); // Create the function - BinaryenType localTypes[] = { BinaryenTypeInt32() }; - BinaryenFunctionRef sinker = BinaryenAddFunction(module, "kitchen()sinker", iiIfF, localTypes, 1, body); + BinaryenType localTypes[] = {BinaryenTypeInt32(), BinaryenTypeExnref()}; + BinaryenFunctionRef sinker = + BinaryenAddFunction(module, "kitchen()sinker", iiIfF, localTypes, 2, body); // Globals BinaryenAddGlobal(module, "a-global", BinaryenTypeInt32(), 0, makeInt32(module, 7)); BinaryenAddGlobal(module, "a-mutable-global", BinaryenTypeFloat32(), 1, makeFloat32(module, 7.5)); - // Events - BinaryenType eparams[1] = { BinaryenTypeInt32() }; - BinaryenFunctionTypeRef vi = BinaryenAddFunctionType(module, "vi", BinaryenTypeNone(), eparams, 1); - BinaryenAddEvent(module, "a-event", 0, vi); - // Imports BinaryenType iparams[2] = { BinaryenTypeInt32(), BinaryenTypeFloat64() }; -- cgit v1.2.3