diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h index a3157fe215..71b8ef0585 100644 --- a/src/wasm/function-body-decoder-impl.h +++ b/src/wasm/function-body-decoder-impl.h @@ -1500,26 +1500,21 @@ class WasmFullDecoder : public WasmDecoder { break; } case kExprCatch: { - // TODO(kschimpf): Fix to use type signature of exception. CHECK_PROTOTYPE_OPCODE(eh); ExceptionIndexImmediate imm(this, this->pc_); - len = 1 + imm.length; - if (!this->Validate(this->pc_, imm)) break; - + len = 1 + imm.length; if (!VALIDATE(!control_.empty())) { this->error("catch does not match any try"); break; } - Control* c = &control_.back(); if (!VALIDATE(c->is_try())) { this->error("catch does not match any try"); break; } - - if (!VALIDATE(c->is_incomplete_try())) { - OPCODE_ERROR(opcode, "multiple catch blocks not implemented"); + if (!VALIDATE(!c->is_try_catchall())) { + this->error("catch after catch-all for try"); break; } c->kind = kControlTryCatch; @@ -1554,7 +1549,6 @@ class WasmFullDecoder : public WasmDecoder { FallThruTo(c); stack_.resize(c->stack_depth); CALL_INTERFACE_IF_PARENT_REACHABLE(CatchAll, c); - // TODO(mstarzinger): Implement control flow for catch-all. break; } case kExprLoop: { diff --git a/test/mjsunit/wasm/exceptions.js b/test/mjsunit/wasm/exceptions.js index f012d10c98..6a7c7e07c5 100644 --- a/test/mjsunit/wasm/exceptions.js +++ b/test/mjsunit/wasm/exceptions.js @@ -103,14 +103,15 @@ function assertWasmThrows(instance, runtime_id, values, code) { assertEquals(42, instance.exports.simple_throw_catch_to_0_1(1)); })(); -// Test that we can distinguish which exception was thrown. -(function TestCatchComplex() { +// Test that we can distinguish which exception was thrown by using a cascaded +// sequence of nested try blocks with a single catch block each. +(function TestCatchComplex1() { print(arguments.callee.name); let builder = new WasmModuleBuilder(); let except1 = builder.addException(kSig_v_v); let except2 = builder.addException(kSig_v_v); let except3 = builder.addException(kSig_v_v); - builder.addFunction("catch_different_exceptions", kSig_i_i) + builder.addFunction("catch_complex", kSig_i_i) .addBody([ kExprTry, kWasmI32, kExprTry, kWasmI32, @@ -134,13 +135,52 @@ function assertWasmThrows(instance, runtime_id, values, code) { kExprEnd, kExprCatch, except2, kExprI32Const, 4, - kExprEnd + kExprEnd, ]).exportFunc(); let instance = builder.instantiate(); - assertEquals(3, instance.exports.catch_different_exceptions(0)); - assertEquals(4, instance.exports.catch_different_exceptions(1)); - assertWasmThrows(instance, except3, [], () => instance.exports.catch_different_exceptions(2)); + assertEquals(3, instance.exports.catch_complex(0)); + assertEquals(4, instance.exports.catch_complex(1)); + assertWasmThrows(instance, except3, [], () => instance.exports.catch_complex(2)); +})(); + +// Test that we can distinguish which exception was thrown by using a single +// try block with multiple associated catch blocks in sequence. +(function TestCatchComplex2() { + print(arguments.callee.name); + let builder = new WasmModuleBuilder(); + let except1 = builder.addException(kSig_v_v); + let except2 = builder.addException(kSig_v_v); + let except3 = builder.addException(kSig_v_v); + builder.addFunction("catch_complex", kSig_i_i) + .addBody([ + kExprTry, kWasmI32, + kExprGetLocal, 0, + kExprI32Eqz, + kExprIf, kWasmStmt, + kExprThrow, except1, + kExprElse, + kExprGetLocal, 0, + kExprI32Const, 1, + kExprI32Eq, + kExprIf, kWasmStmt, + kExprThrow, except2, + kExprElse, + kExprThrow, except3, + kExprEnd, + kExprEnd, + kExprI32Const, 2, + kExprCatch, except1, + kExprI32Const, 3, + kExprCatch, except2, + kExprI32Const, 4, + kExprEnd, + ]).exportFunc(); + let instance = builder.instantiate(); + + assertEquals(3, instance.exports.catch_complex(0)); + assertEquals(4, instance.exports.catch_complex(1)); + assertWasmThrows(instance, except3, [], () => instance.exports.catch_complex(2)); })(); // Test throwing an exception with multiple values. diff --git a/test/unittests/wasm/function-body-decoder-unittest.cc b/test/unittests/wasm/function-body-decoder-unittest.cc index 31e4a12ae7..35ba2292d2 100644 --- a/test/unittests/wasm/function-body-decoder-unittest.cc +++ b/test/unittests/wasm/function-body-decoder-unittest.cc @@ -2438,12 +2438,10 @@ TEST_F(FunctionBodyDecoderTest, TryCatch) { byte ex1 = builder.AddException(sigs.v_v()); byte ex2 = builder.AddException(sigs.v_v()); EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), kExprEnd); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), WASM_CATCH(ex2), kExprEnd); EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprEnd); // Missing catch. EXPECT_FAILURE(v_v, WASM_TRY_OP, WASM_CATCH(ex1)); // Missing end. EXPECT_FAILURE(v_v, WASM_CATCH(ex1), kExprEnd); // Missing try. - - // TODO(mstarzinger): Double catch. Fix this to verify. - EXPECT_FAILURE(v_v, WASM_TRY_OP, WASM_CATCH(ex1), WASM_CATCH(ex2), kExprEnd); } TEST_F(FunctionBodyDecoderTest, TryCatchAll) { @@ -2451,8 +2449,11 @@ TEST_F(FunctionBodyDecoderTest, TryCatchAll) { TestModuleBuilder builder; module = builder.module(); byte ex1 = builder.AddException(sigs.v_v()); + byte ex2 = builder.AddException(sigs.v_v()); EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatchAll, kExprEnd); EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), kExprCatchAll, kExprEnd); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), WASM_CATCH(ex2), + kExprCatchAll, kExprEnd); EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll, kExprCatchAll, kExprEnd); EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll, WASM_CATCH(ex1), kExprEnd); EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll); // Missing end.