[wasm] Add support for multiple catch blocks.
This adds support for multiple catch blocks being attached to a single try block. The implemented semantics are that type checks are performed in order from top to bottom. Note that multiple catch blocks of the same type are not prohibited and will be accepted, making the second such block essentially unreachable. The current proposal neither explicitly allows nor prohibits it. R=clemensh@chromium.org TEST=mjsunit/wasm/exceptions BUG=v8:8091 Change-Id: I31e7a07a7cffdd909a58342e00f05e52ed1a3182 Reviewed-on: https://chromium-review.googlesource.com/c/1270591 Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#56478}
This commit is contained in:
parent
f8375f480e
commit
2e007737ca
@ -1500,26 +1500,21 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
break;
|
||||
}
|
||||
case kExprCatch: {
|
||||
// TODO(kschimpf): Fix to use type signature of exception.
|
||||
CHECK_PROTOTYPE_OPCODE(eh);
|
||||
ExceptionIndexImmediate<validate> 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<validate> {
|
||||
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: {
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user