[wasm] Add test for handling "unreachable" trap.
This adds a test case to check consistency of how an "unreachable" trap is handled by a surrounding "try" block in case those two operations are in different functions (i.e. not local to one function body). It also fixes a DCHECK for an as-of-yet untested interpreter state transition. R=clemensh@chromium.org TEST=cctest/test-run-wasm-exceptions BUG=v8:8729 Change-Id: I432c48d0bc664f7ab092aaafef6dfa29c5f262fd Reviewed-on: https://chromium-review.googlesource.com/c/1454605 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#59429}
This commit is contained in:
parent
b3726e9041
commit
0999709cf2
@ -215,9 +215,7 @@ class InterpreterHandle {
|
||||
WasmOpcodes::TrapReasonToMessageId(thread->GetTrapReason());
|
||||
Handle<Object> exception =
|
||||
isolate_->factory()->NewWasmRuntimeError(message_id);
|
||||
isolate_->Throw(*exception);
|
||||
// Handle this exception locally within the activation.
|
||||
auto result = thread->HandleException(isolate_);
|
||||
auto result = thread->RaiseException(isolate_, exception);
|
||||
if (result == WasmInterpreter::Thread::HANDLED) break;
|
||||
// If no local handler was found, we fall-thru to {STOPPED}.
|
||||
DCHECK_EQ(WasmInterpreter::State::STOPPED, thread->state());
|
||||
|
@ -1267,6 +1267,19 @@ class ThreadImpl {
|
||||
return activations_[id].fp;
|
||||
}
|
||||
|
||||
WasmInterpreter::Thread::ExceptionHandlingResult RaiseException(
|
||||
Isolate* isolate, Handle<Object> exception) {
|
||||
DCHECK_EQ(WasmInterpreter::TRAPPED, state_);
|
||||
isolate->Throw(*exception); // Will check that none is pending.
|
||||
if (HandleException(isolate) == WasmInterpreter::Thread::UNWOUND) {
|
||||
DCHECK_EQ(WasmInterpreter::STOPPED, state_);
|
||||
return WasmInterpreter::Thread::UNWOUND;
|
||||
}
|
||||
state_ = WasmInterpreter::PAUSED;
|
||||
return WasmInterpreter::Thread::HANDLED;
|
||||
}
|
||||
|
||||
private:
|
||||
// Handle a thrown exception. Returns whether the exception was handled inside
|
||||
// the current activation. Unwinds the interpreted stack accordingly.
|
||||
WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
|
||||
@ -1301,7 +1314,6 @@ class ThreadImpl {
|
||||
return WasmInterpreter::Thread::UNWOUND;
|
||||
}
|
||||
|
||||
private:
|
||||
// Entries on the stack of functions being evaluated.
|
||||
struct Frame {
|
||||
InterpreterCode* code;
|
||||
@ -3283,8 +3295,9 @@ WasmInterpreter::State WasmInterpreter::Thread::Run(int num_steps) {
|
||||
void WasmInterpreter::Thread::Pause() { return ToImpl(this)->Pause(); }
|
||||
void WasmInterpreter::Thread::Reset() { return ToImpl(this)->Reset(); }
|
||||
WasmInterpreter::Thread::ExceptionHandlingResult
|
||||
WasmInterpreter::Thread::HandleException(Isolate* isolate) {
|
||||
return ToImpl(this)->HandleException(isolate);
|
||||
WasmInterpreter::Thread::RaiseException(Isolate* isolate,
|
||||
Handle<Object> exception) {
|
||||
return ToImpl(this)->RaiseException(isolate, exception);
|
||||
}
|
||||
pc_t WasmInterpreter::Thread::GetBreakpointPc() {
|
||||
return ToImpl(this)->GetBreakpointPc();
|
||||
|
@ -85,13 +85,14 @@ struct InterpretedFrameDeleter {
|
||||
class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
public:
|
||||
// State machine for a Thread:
|
||||
// +---------Run()/Step()--------+
|
||||
// V |
|
||||
// STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED
|
||||
// ^ | | | | /
|
||||
// +- HandleException -+ | | +--- Breakpoint ---+
|
||||
// | |
|
||||
// | +---------- Trap --------------> TRAPPED
|
||||
// +----------------------------------------------------------+
|
||||
// | +--------Run()/Step()---------+ |
|
||||
// V V | |
|
||||
// STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED <--+
|
||||
// ^ | | | | / |
|
||||
// +--- Exception ---+ | | +--- Breakpoint ---+ RaiseException() <--+
|
||||
// | | |
|
||||
// | +---------- Trap --------------> TRAPPED --------+
|
||||
// +----------- Finish -------------> FINISHED
|
||||
enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
|
||||
|
||||
@ -121,9 +122,12 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
State Step() { return Run(1); }
|
||||
void Pause();
|
||||
void Reset();
|
||||
// Handle the pending exception in the passed isolate. Unwind the stack
|
||||
// accordingly. Return whether the exception was handled inside wasm.
|
||||
ExceptionHandlingResult HandleException(Isolate* isolate);
|
||||
|
||||
// Raise an exception in the current activation and unwind the stack
|
||||
// accordingly. Return whether the exception was handled inside wasm:
|
||||
// - HANDLED: Activation at handler position and in {PAUSED} state.
|
||||
// - UNWOUND: Frames unwound, exception pending, and in {STOPPED} state.
|
||||
ExceptionHandlingResult RaiseException(Isolate*, Handle<Object> exception);
|
||||
|
||||
// Stack inspection and modification.
|
||||
pc_t GetBreakpointPc();
|
||||
|
@ -158,6 +158,37 @@ WASM_EXEC_TEST(TryCatchTrapTypeError) {
|
||||
r.CheckCallViaJS(kResult1, 1);
|
||||
}
|
||||
|
||||
// TODO(8729): The semantics of this are not yet specified and might change,
|
||||
// this test aims at keeping semantics of various execution tiers consistent.
|
||||
// TODO(mstarzinger): Add further tests for different kinds of traps.
|
||||
WASM_EXEC_TEST(TryCatchTrapUnreachable) {
|
||||
TestSignatures sigs;
|
||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
||||
WasmRunner<uint32_t, uint32_t> r(execution_tier, nullptr, "main",
|
||||
kRuntimeExceptionSupport);
|
||||
constexpr uint32_t kResult0 = 23;
|
||||
constexpr uint32_t kResult1 = 42;
|
||||
|
||||
// Build a trapping helper function.
|
||||
WasmFunctionCompiler& trap_func = r.NewFunction(sigs.i_ii());
|
||||
BUILD(trap_func, WASM_UNREACHABLE);
|
||||
|
||||
// Build the main test function.
|
||||
BUILD(r, WASM_TRY_CATCH_T(
|
||||
kWasmI32,
|
||||
WASM_STMTS(WASM_I32V(kResult1),
|
||||
WASM_IF(WASM_I32_EQZ(WASM_GET_LOCAL(0)),
|
||||
WASM_STMTS(WASM_CALL_FUNCTION(
|
||||
trap_func.function_index(),
|
||||
WASM_I32V(7), WASM_I32V(9)),
|
||||
WASM_DROP))),
|
||||
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
|
||||
|
||||
// Need to call through JS to allow for creation of stack traces.
|
||||
r.CheckCallViaJS(kResult0, 0);
|
||||
r.CheckCallViaJS(kResult1, 1);
|
||||
}
|
||||
|
||||
} // namespace test_run_wasm_exceptions
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
|
@ -438,7 +438,7 @@ TEST(TestPossibleNondeterminism) {
|
||||
TEST(WasmInterpreterActivations) {
|
||||
WasmRunner<void> r(ExecutionTier::kInterpreter);
|
||||
Isolate* isolate = r.main_isolate();
|
||||
BUILD(r, WASM_NOP);
|
||||
BUILD(r, WASM_UNREACHABLE);
|
||||
|
||||
WasmInterpreter* interpreter = r.interpreter();
|
||||
WasmInterpreter::Thread* thread = interpreter->GetThread(0);
|
||||
@ -451,17 +451,20 @@ TEST(WasmInterpreterActivations) {
|
||||
thread->InitFrame(r.function(), nullptr);
|
||||
CHECK_EQ(2, thread->NumActivations());
|
||||
CHECK_EQ(2, thread->GetFrameCount());
|
||||
isolate->set_pending_exception(Smi::kZero);
|
||||
thread->HandleException(isolate);
|
||||
CHECK_EQ(WasmInterpreter::TRAPPED, thread->Run());
|
||||
thread->RaiseException(isolate, handle(Smi::kZero, isolate));
|
||||
CHECK_EQ(1, thread->GetFrameCount());
|
||||
CHECK_EQ(2, thread->NumActivations());
|
||||
thread->FinishActivation(act1);
|
||||
isolate->clear_pending_exception();
|
||||
CHECK_EQ(1, thread->GetFrameCount());
|
||||
CHECK_EQ(1, thread->NumActivations());
|
||||
thread->HandleException(isolate);
|
||||
CHECK_EQ(WasmInterpreter::TRAPPED, thread->Run());
|
||||
thread->RaiseException(isolate, handle(Smi::kZero, isolate));
|
||||
CHECK_EQ(0, thread->GetFrameCount());
|
||||
CHECK_EQ(1, thread->NumActivations());
|
||||
thread->FinishActivation(act0);
|
||||
isolate->clear_pending_exception();
|
||||
CHECK_EQ(0, thread->NumActivations());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user