summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-07-29 14:35:46 -0700
committerIan Rogers <irogers@google.com>2013-07-29 14:45:07 -0700
commitc449aa8151bf81d93d22ff24677ccf09a6da218e (patch)
tree343274bb1e635bc503ae0ffc44c68ec44f6b69e5
parentc95d6b1cb35b382804b9a310d32f66059eca65d9 (diff)
downloadart-c449aa8151bf81d93d22ff24677ccf09a6da218e.zip
art-c449aa8151bf81d93d22ff24677ccf09a6da218e.tar.gz
art-c449aa8151bf81d93d22ff24677ccf09a6da218e.tar.bz2
Clear exception if catch block doesn't have move-exception.
Bug: 10040419 Change-Id: Icc7a55cb3cdfbc3efd2b161bbe22b3e5007de35f
-rw-r--r--runtime/interpreter/interpreter.cc7
-rw-r--r--runtime/mirror/abstract_method.cc10
-rw-r--r--runtime/mirror/abstract_method.h6
-rw-r--r--runtime/runtime_support_llvm.cc6
-rw-r--r--runtime/thread.cc15
-rw-r--r--runtime/verifier/method_verifier.cc6
6 files changed, 35 insertions, 15 deletions
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 8d7d028..37c45fa 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -975,7 +975,9 @@ static inline const Instruction* FindNextInstructionFollowingException(Thread* s
self->VerifyStack();
ThrowLocation throw_location;
mirror::Throwable* exception = self->GetException(&throw_location);
- uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc);
+ bool clear_exception;
+ uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
+ &clear_exception);
if (found_dex_pc == DexFile::kDexNoIndex) {
instrumentation->MethodUnwindEvent(self, this_object_ref.get(),
shadow_frame.GetMethod(), dex_pc);
@@ -984,6 +986,9 @@ static inline const Instruction* FindNextInstructionFollowingException(Thread* s
instrumentation->ExceptionCaughtEvent(self, throw_location,
shadow_frame.GetMethod(),
found_dex_pc, exception);
+ if (clear_exception) {
+ self->ClearException();
+ }
return Instruction::At(insns + found_dex_pc);
}
}
diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc
index 58ef5f7..d08708f 100644
--- a/runtime/mirror/abstract_method.cc
+++ b/runtime/mirror/abstract_method.cc
@@ -20,6 +20,7 @@
#include "base/stringpiece.h"
#include "class-inl.h"
#include "dex_file-inl.h"
+#include "dex_instruction.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
#include "jni_internal.h"
@@ -225,7 +226,8 @@ uintptr_t AbstractMethod::ToNativePc(const uint32_t dex_pc) const {
return 0;
}
-uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const {
+uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc,
+ bool* has_no_move_exception) const {
MethodHelper mh(this);
const DexFile::CodeItem* code_item = mh.GetCodeItem();
// Iterate over the catch handlers associated with dex_pc
@@ -242,7 +244,11 @@ uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc)
LOG(WARNING) << "Unresolved exception class when finding catch block: "
<< mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
} else if (iter_exception_type->IsAssignableFrom(exception_type)) {
- return it.GetHandlerAddress();
+ uint32_t found_dex_pc = it.GetHandlerAddress();
+ const Instruction* first_catch_instr =
+ Instruction::At(&mh.GetCodeItem()->insns_[found_dex_pc]);
+ *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
+ return found_dex_pc;
}
}
// Handler not found
diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h
index bbebece..2e6e262 100644
--- a/runtime/mirror/abstract_method.h
+++ b/runtime/mirror/abstract_method.h
@@ -407,8 +407,10 @@ class MANAGED AbstractMethod : public Object {
uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc)
const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Find the catch block for the given exception type and dex_pc
- uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const
+ // Find the catch block for the given exception type and dex_pc. When a catch block is found,
+ // indicates whether the found catch block is responsible for clearing the exception or whether
+ // a move-exception instruction is present.
+ uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc, bool* has_no_move_exception) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method);
diff --git a/runtime/runtime_support_llvm.cc b/runtime/runtime_support_llvm.cc
index 713bc40..93396d6 100644
--- a/runtime/runtime_support_llvm.cc
+++ b/runtime/runtime_support_llvm.cc
@@ -324,6 +324,12 @@ int32_t art_portable_find_catch_block_from_code(AbstractMethod* current_method,
current_method,
catch_dex_pc,
exception);
+ // If the catch block has no move-exception then clear the exception for it.
+ const Instruction* first_catch_instr =
+ Instruction::At(&mh.GetCodeItem()->insns_[catch_dex_pc]);
+ if (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION) {
+ self->ClearException();
+ }
}
return result;
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index ea12c2e..d5fdd20 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1709,7 +1709,7 @@ class CatchBlockStackVisitor : public StackVisitor {
self_(self), exception_(exception), is_deoptimization_(is_deoptimization),
to_find_(is_deoptimization ? NULL : exception->GetClass()), throw_location_(throw_location),
handler_quick_frame_(NULL), handler_quick_frame_pc_(0), handler_dex_pc_(0),
- native_method_count_(0),
+ native_method_count_(0), clear_exception_(false),
method_tracing_active_(is_deoptimization ||
Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
instrumentation_frames_to_pop_(0), top_shadow_frame_(NULL), prev_shadow_frame_(NULL) {
@@ -1754,7 +1754,7 @@ class CatchBlockStackVisitor : public StackVisitor {
dex_pc = GetDexPc();
}
if (dex_pc != DexFile::kDexNoIndex) {
- uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
+ uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception_);
if (found_dex_pc != DexFile::kDexNoIndex) {
handler_dex_pc_ = found_dex_pc;
handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc);
@@ -1820,8 +1820,13 @@ class CatchBlockStackVisitor : public StackVisitor {
LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
}
}
- // Put exception back in root set and clear throw location.
- self_->SetException(ThrowLocation(), exception_);
+ if (clear_exception_) {
+ // Exception was cleared as part of delivery.
+ DCHECK(!self_->IsExceptionPending());
+ } else {
+ // Put exception back in root set with clear throw location.
+ self_->SetException(ThrowLocation(), exception_);
+ }
self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
// Do instrumentation events after allowing thread suspension again.
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
@@ -1864,6 +1869,8 @@ class CatchBlockStackVisitor : public StackVisitor {
uint32_t handler_dex_pc_;
// Number of native methods passed in crawl (equates to number of SIRTs to pop)
uint32_t native_method_count_;
+ // Should the exception be cleared as the catch block has no move-exception?
+ bool clear_exception_;
// Is method tracing active?
const bool method_tracing_active_;
// Support for nesting no thread suspension checks.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1481ad9..9f0d911 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -555,12 +555,6 @@ bool MethodVerifier::ScanTryCatchBlocks() {
<< "exception handler starts at bad address (" << dex_pc << ")";
return false;
}
- const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
- if (inst->Opcode() != Instruction::MOVE_EXCEPTION) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler doesn't start with move-exception ("
- << dex_pc << ")";
- return false;
- }
insn_flags_[dex_pc].SetBranchTarget();
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery