Commit 5b8c7f84 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Support exceptions between interpreter frames.

This adds support for handling exceptions between different frames of
one single interpreter activation. Frames are dropped until a local
handler is found. If none is found in the current activation then we
delegate to the existing stack unwinding mechanism to deal with multiple
activations interspersed with non-interpreter stack frames on the actual
machine stack.

R=clemensh@chromium.org
TEST=cctest/test-run-wasm-exceptions
BUG=v8:8091

Change-Id: Ia4abb27ff037bf0d3e3b05721bd3c971ef820e3c
Reviewed-on: https://chromium-review.googlesource.com/c/1445989
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59228}
parent 142225ac
......@@ -1272,23 +1272,31 @@ class ThreadImpl {
WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
Isolate* isolate) {
DCHECK(isolate->has_pending_exception());
InterpreterCode* code = frames_.back().code;
if (code->side_table->HasEntryAt(frames_.back().pc)) {
TRACE("----- HANDLE -----\n");
// TODO(mstarzinger): Push a reference to the pending exception instead of
// the bogus {int32_t(0)} value here once the interpreter supports it.
USE(isolate->pending_exception());
Push(WasmValue(int32_t{0}));
isolate->clear_pending_exception();
return WasmInterpreter::Thread::HANDLED;
}
TRACE("----- UNWIND -----\n");
DCHECK_LT(0, activations_.size());
Activation& act = activations_.back();
DCHECK_LE(act.fp, frames_.size());
frames_.resize(act.fp);
DCHECK_LE(act.sp, StackHeight());
sp_ = stack_.get() + act.sp;
while (frames_.size() > act.fp) {
Frame& frame = frames_.back();
InterpreterCode* code = frame.code;
if (code->side_table->HasEntryAt(frame.pc)) {
TRACE("----- HANDLE -----\n");
// TODO(mstarzinger): Push a reference to the pending exception instead
// of a bogus {int32_t(0)} value here once the interpreter supports it.
USE(isolate->pending_exception());
Push(WasmValue(int32_t{0}));
isolate->clear_pending_exception();
frame.pc += JumpToHandlerDelta(code, frame.pc);
TRACE(" => handler #%zu (#%u @%zu)\n", frames_.size() - 1,
code->function->func_index, frame.pc);
return WasmInterpreter::Thread::HANDLED;
}
TRACE(" => drop frame #%zu (#%u @%zu)\n", frames_.size() - 1,
code->function->func_index, frame.pc);
sp_ = stack_.get() + frame.sp;
frames_.pop_back();
}
TRACE("----- UNWIND -----\n");
DCHECK_EQ(act.fp, frames_.size());
DCHECK_EQ(act.sp, StackHeight());
state_ = WasmInterpreter::STOPPED;
return WasmInterpreter::Thread::UNWOUND;
}
......@@ -1391,6 +1399,16 @@ class ThreadImpl {
return false;
}
void ReloadFromFrameOnException(Decoder* decoder, InterpreterCode** code,
pc_t* pc, pc_t* limit, int* len) {
Frame* top = &frames_.back();
*code = top->code;
*pc = top->pc;
*limit = top->code->end - top->code->start;
decoder->Reset(top->code->start, top->code->end);
*len = 0; // The {pc} has already been set correctly.
}
int LookupTargetDelta(InterpreterCode* code, pc_t pc) {
return static_cast<int>(code->side_table->Lookup(pc).pc_diff);
}
......@@ -2394,14 +2412,14 @@ class ThreadImpl {
CommitPc(pc); // Needed for local unwinding.
const WasmException* exception = &module()->exceptions[imm.index];
if (!DoThrowException(exception, imm.index)) return;
len = JumpToHandlerDelta(code, pc);
ReloadFromFrameOnException(&decoder, &code, &pc, &limit, &len);
break;
}
case kExprRethrow: {
WasmValue ex = Pop();
CommitPc(pc); // Needed for local unwinding.
if (!DoRethrowException(&ex)) return;
len = JumpToHandlerDelta(code, pc);
ReloadFromFrameOnException(&decoder, &code, &pc, &limit, &len);
break;
}
case kExprSelect: {
......@@ -2533,7 +2551,7 @@ class ThreadImpl {
case ExternalCallResult::EXTERNAL_UNWOUND:
return;
case ExternalCallResult::EXTERNAL_CAUGHT:
len = JumpToHandlerDelta(code, pc);
ReloadFromFrameOnException(&decoder, &code, &pc, &limit, &len);
DCHECK(exception_was_thrown = true);
break;
}
......@@ -2573,7 +2591,7 @@ class ThreadImpl {
case ExternalCallResult::EXTERNAL_UNWOUND:
return;
case ExternalCallResult::EXTERNAL_CAUGHT:
len = JumpToHandlerDelta(code, pc);
ReloadFromFrameOnException(&decoder, &code, &pc, &limit, &len);
DCHECK(exception_was_thrown = true);
break;
}
......
......@@ -56,8 +56,7 @@ WASM_EXEC_TEST(TryCatchCallDirect) {
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
// Need to call through JS to allow for creation of stack traces.
// TODO(mstarzinger): Enable the below tests once implemented.
// r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult1, 1);
}
......@@ -94,8 +93,7 @@ WASM_EXEC_TEST(TryCatchCallIndirect) {
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
// Need to call through JS to allow for creation of stack traces.
// TODO(mstarzinger): Enable the below tests once implemented.
// r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult1, 1);
}
......
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