diff options
-rw-r--r-- | runtime/interpreter/interpreter.cc | 7 | ||||
-rw-r--r-- | runtime/mirror/abstract_method.cc | 10 | ||||
-rw-r--r-- | runtime/mirror/abstract_method.h | 6 | ||||
-rw-r--r-- | runtime/runtime_support_llvm.cc | 6 | ||||
-rw-r--r-- | runtime/thread.cc | 15 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 6 |
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 |