summaryrefslogtreecommitdiffstats
path: root/runtime/interpreter
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2015-01-16 19:49:09 +0100
committerSebastien Hertz <shertz@google.com>2015-01-23 17:26:45 +0100
commit270a0e16c3b8e5b95cbfdbd8996ac137c7c6322b (patch)
tree2800649d19ffcdc891118a458f6b0169022d93e0 /runtime/interpreter
parent951d70b42400453f9d1746d155b8337c07c86acc (diff)
downloadandroid_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.cc18
-rw-r--r--runtime/interpreter/interpreter_goto_table_impl.cc6
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc6
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();