diff options
author | Sebastien Hertz <shertz@google.com> | 2015-01-16 19:49:09 +0100 |
---|---|---|
committer | Sebastien Hertz <shertz@google.com> | 2015-01-23 17:26:45 +0100 |
commit | 270a0e16c3b8e5b95cbfdbd8996ac137c7c6322b (patch) | |
tree | 2800649d19ffcdc891118a458f6b0169022d93e0 /runtime/interpreter | |
parent | 951d70b42400453f9d1746d155b8337c07c86acc (diff) | |
download | android_art-270a0e16c3b8e5b95cbfdbd8996ac137c7c6322b.tar.gz android_art-270a0e16c3b8e5b95cbfdbd8996ac137c7c6322b.tar.bz2 android_art-270a0e16c3b8e5b95cbfdbd8996ac137c7c6322b.zip |
Fix exception handling during deoptimization
When interpreting a deoptimized shadow frame, we may start with a
pending exception thrown by a previous deoptimized shadow frame (from
a previous invoke). Therefore, we need to handle it before executing
any instruction, otherwise we execute incorrect code.
Because we need the DEX pc of the throwing instruction to find a
matching catch handler, we initialize deoptimized shadow frames with
the current DEX pc at the time the stack is deoptimized.
When we are about to interpret a deoptimized shadow frame, we need to
update the shadow frame with the DEX pc of the next instruction to
interpret. There are three cases:
- if there is no pending exception, this is the instruction following
the current one.
- if there is a pending exception and we found a matching catch
handler, this is the first instruction of this handler.
- if there is a pending exception but there is no matching catch
handler, we do not execute the deoptimized shadow frame and continue
to its caller.
The verifier now fails when a method starts with a move-exception
instruction. Indeed we cannot start executing a method with a pending
exception.
Bug: 19057915
Bug: 19041195
Bug: 18607595
Change-Id: I355ac81e6ac098edc7e3cc8c13dbfa24a2969ab2
Diffstat (limited to 'runtime/interpreter')
-rw-r--r-- | runtime/interpreter/interpreter.cc | 18 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_goto_table_impl.cc | 6 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 6 |
3 files changed, 27 insertions, 3 deletions
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index b04a18b934..9d988e978d 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -493,7 +493,23 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JVa while (shadow_frame != NULL) { self->SetTopOfShadowStack(shadow_frame); const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem(); - value = Execute(self, code_item, *shadow_frame, value); + const uint32_t dex_pc = shadow_frame->GetDexPC(); + uint32_t new_dex_pc; + if (UNLIKELY(self->IsExceptionPending())) { + const instrumentation::Instrumentation* const instrumentation = + Runtime::Current()->GetInstrumentation(); + uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame, dex_pc, + instrumentation); + new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler + // or DexFile::kDexNoIndex if there is none. + } else { + const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); + new_dex_pc = dex_pc + instr->SizeInCodeUnits(); // the dex pc of the next instruction. + } + if (new_dex_pc != DexFile::kDexNoIndex) { + shadow_frame->SetDexPC(new_dex_pc); + value = Execute(self, code_item, *shadow_frame, value); + } ShadowFrame* old_frame = shadow_frame; shadow_frame = shadow_frame->GetLink(); delete old_frame; diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc index 8fcbf908a2..e4b324792e 100644 --- a/runtime/interpreter/interpreter_goto_table_impl.cc +++ b/runtime/interpreter/interpreter_goto_table_impl.cc @@ -148,7 +148,10 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF const void* const* currentHandlersTable; bool notified_method_entry_event = false; UPDATE_HANDLER_TABLE(); - if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing.. + if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing. + if (kIsDebugBuild) { + self->AssertNoPendingException(); + } instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodEntryListeners())) { instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), @@ -236,6 +239,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF HANDLE_INSTRUCTION_START(MOVE_EXCEPTION) { Throwable* exception = self->GetException(nullptr); + DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction"; shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception); self->ClearException(); ADVANCE(1); diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 38665c7e0b..2f85587604 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -69,7 +69,10 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, uint32_t dex_pc = shadow_frame.GetDexPC(); bool notified_method_entry_event = false; const instrumentation::Instrumentation* const instrumentation = Runtime::Current()->GetInstrumentation(); - if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing.. + if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing. + if (kIsDebugBuild) { + self->AssertNoPendingException(); + } if (UNLIKELY(instrumentation->HasMethodEntryListeners())) { instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), 0); @@ -161,6 +164,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, case Instruction::MOVE_EXCEPTION: { PREAMBLE(); Throwable* exception = self->GetException(nullptr); + DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction"; shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception); self->ClearException(); inst = inst->Next_1xx(); |