Commit 22a683f5 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Commit Bot

[wasm][interpreter][eh] Implement unwind

R=clemensb@chromium.org

Bug: v8:8091
Change-Id: I2933342da65ef75cfe36f81f8828411fd78d45e8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2696659
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72790}
parent a38039a7
......@@ -2074,6 +2074,7 @@ class WasmDecoder : public Decoder {
case kExprTry:
case kExprCatch:
case kExprDelegate:
case kExprUnwind:
case kExprRethrow:
case kExprNop:
case kExprNopForTestingUnsupportedInLiftoff:
......
......@@ -187,6 +187,38 @@ WASM_EXEC_TEST(TryDelegate) {
}
}
WASM_EXEC_TEST(TryUnwind) {
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(eh);
WasmRunner<uint32_t, uint32_t> r(execution_tier);
uint32_t except = r.builder().AddException(sigs.v_v());
constexpr uint32_t kResult0 = 23;
constexpr uint32_t kResult1 = 42;
// Build the main test function.
BUILD(r, WASM_TRY_CATCH_T(
kWasmI32,
WASM_TRY_UNWIND_T(
kWasmI32,
WASM_TRY_DELEGATE_T(
kWasmI32,
WASM_STMTS(WASM_I32V(kResult1),
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
WASM_THROW(except))),
0),
kExprNop),
WASM_I32V(kResult0), except));
if (execution_tier != TestExecutionTier::kInterpreter) {
// Need to call through JS to allow for creation of stack traces.
r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult1, 1);
} else {
CHECK_EQ(kResult0, r.CallInterpreter(0));
CHECK_EQ(kResult1, r.CallInterpreter(1));
}
}
WASM_EXEC_TEST(TryCatchRethrow) {
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(eh);
......
......@@ -695,6 +695,9 @@ class SideTable : public ZoneObject {
// Track whether this block was already left, i.e. all further
// instructions are unreachable.
bool unreachable = false;
// Whether this is a try...unwind...end block. Needed to handle the
// implicit rethrow when we reach the end of the block.
bool unwind = false;
Control(const byte* pc, CLabel* end_label, CLabel* else_label,
uint32_t exit_arity)
......@@ -857,6 +860,27 @@ class SideTable : public ZoneObject {
}
break;
}
case kExprUnwind: {
Control* c = &control_stack.back();
DCHECK_EQ(*c->pc, kExprTry);
DCHECK(!exception_stack.empty());
DCHECK_EQ(exception_stack.back(), control_stack.size() - 1);
exception_stack.pop_back();
copy_unreachable();
TRACE("control @%u: Unwind\n", i.pc_offset());
if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
DCHECK_NOT_NULL(c->else_label);
int control_index = static_cast<int>(control_stack.size()) - 1;
c->else_label->Bind(i.pc() + 1, kCatchAllExceptionIndex,
control_index);
c->else_label->Finish(&map_, code->start);
c->else_label = nullptr;
c->unwind = true;
DCHECK_IMPLIES(!unreachable,
stack_height >= c->end_label->target_stack_height);
stack_height = c->end_label->target_stack_height;
break;
}
case kExprTry: {
BlockTypeImmediate<Decoder::kNoValidation> imm(
WasmFeatures::All(), &i, i.pc() + 1, module);
......@@ -929,6 +953,17 @@ class SideTable : public ZoneObject {
i.pc(), c->else_label->target_stack_height);
}
}
} else if (c->unwind) {
DCHECK_EQ(*c->pc, kExprTry);
rethrow_map_.emplace(i.pc() - i.start(),
static_cast<int>(control_stack.size()) - 1);
if (!exception_stack.empty()) {
Control* next_try_block =
&control_stack[exception_stack.back()];
if (!unreachable) {
next_try_block->else_label->Ref(i.pc(), stack_height);
}
}
}
c->end_label->Bind(i.pc() + 1);
}
......@@ -3436,6 +3471,7 @@ class WasmInterpreterInternals {
break;
}
case kExprElse:
case kExprUnwind:
case kExprCatch: {
len = LookupTargetDelta(code, pc);
TRACE(" end => @%zu\n", pc + len);
......@@ -3531,6 +3567,19 @@ class WasmInterpreterInternals {
break;
}
case kExprEnd: {
if (code->side_table->rethrow_map_.count(pc)) {
// Implicit rethrow after unwind.
HandleScope scope(isolate_);
DCHECK(!frames_.back().caught_exception_stack.is_null());
int index = code->side_table->rethrow_map_[pc];
Handle<Object> exception = handle(
frames_.back().caught_exception_stack->get(index), isolate_);
DCHECK(!exception->IsTheHole());
CommitPc(pc); // Needed for local unwinding.
if (!DoRethrowException(exception)) return;
ReloadFromFrameOnException(&decoder, &code, &pc, &limit);
continue; // Do not bump pc.
}
break;
}
case kExprI32Const: {
......
......@@ -197,6 +197,9 @@
#define WASM_TRY_DELEGATE_T(t, trystmt, depth) \
kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprDelegate, \
depth
#define WASM_TRY_UNWIND_T(t, trystmt, unwindstmt) \
kExprTry, static_cast<byte>((t).value_type_code()), trystmt, kExprUnwind, \
unwindstmt, kExprEnd
#define WASM_SELECT(tval, fval, cond) tval, fval, cond, kExprSelect
#define WASM_SELECT_I(tval, fval, cond) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment