diff options
| author | 2014-05-30 19:53:48 +0000 | |
|---|---|---|
| committer | 2014-05-30 19:53:48 +0000 | |
| commit | b413cd79c46b7c48ac763cb8152a55a4ed60fe9f (patch) | |
| tree | d4f09efe7ba5eb3891d26f3a8b1033b02bb72328 /runtime/quick_exception_handler.cc | |
| parent | 22460ecbaae7e489a3bc17a2adb2e7e9d0028f9c (diff) | |
| parent | 5cf98196d488437acd1e989c08a554ef697fded1 (diff) | |
Merge "Don't report down-calls as unhandled exceptions."
Diffstat (limited to 'runtime/quick_exception_handler.cc')
| -rw-r--r-- | runtime/quick_exception_handler.cc | 186 | 
1 files changed, 174 insertions, 12 deletions
| diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 243818c4a2..b9cec40ebf 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -16,25 +16,105 @@  #include "quick_exception_handler.h" -#include "catch_block_stack_visitor.h" -#include "deoptimize_stack_visitor.h" +#include "dex_instruction.h"  #include "entrypoints/entrypoint_utils.h" -#include "mirror/art_method-inl.h"  #include "handle_scope-inl.h" +#include "mirror/art_method-inl.h" +#include "verifier/method_verifier.h"  namespace art { +static constexpr bool kDebugExceptionDelivery = false; +static constexpr size_t kInvalidFrameId = 0xffffffff; +  QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)    : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization),      method_tracing_active_(is_deoptimization ||                             Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()), -    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_dex_pc_(0), -    clear_exception_(false), handler_frame_id_(kInvalidFrameId) { +    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_method_(nullptr), +    handler_dex_pc_(0), clear_exception_(false), handler_frame_id_(kInvalidFrameId) {  } +// Finds catch handler or prepares for deoptimization. +class CatchBlockStackVisitor FINAL : public StackVisitor { + public: +  CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception, +                         QuickExceptionHandler* exception_handler) +      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) +      : StackVisitor(self, context), self_(self), exception_(exception), +        exception_handler_(exception_handler) { +  } + +  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    mirror::ArtMethod* method = GetMethod(); +    exception_handler_->SetHandlerFrameId(GetFrameId()); +    if (method == nullptr) { +      // This is the upcall, we remember the frame and last pc so that we may long jump to them. +      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc()); +      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); +      uint32_t next_dex_pc; +      mirror::ArtMethod* next_art_method; +      bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc); +      // Report the method that did the down call as the handler. +      exception_handler_->SetHandlerDexPc(next_dex_pc); +      exception_handler_->SetHandlerMethod(next_art_method); +      if (!has_next) { +        // No next method? Check exception handler is set up for the unhandled exception handler +        // case. +        DCHECK_EQ(0U, exception_handler_->GetHandlerDexPc()); +        DCHECK(nullptr == exception_handler_->GetHandlerMethod()); +      } +      return false;  // End stack walk. +    } +    if (method->IsRuntimeMethod()) { +      // Ignore callee save method. +      DCHECK(method->IsCalleeSaveMethod()); +      return true; +    } +    return HandleTryItems(method); +  } + + private: +  bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    uint32_t dex_pc = DexFile::kDexNoIndex; +    if (!method->IsNative()) { +      dex_pc = GetDexPc(); +    } +    if (dex_pc != DexFile::kDexNoIndex) { +      bool clear_exception = false; +      StackHandleScope<1> hs(Thread::Current()); +      Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass())); +      uint32_t found_dex_pc = method->FindCatchBlock(to_find, dex_pc, &clear_exception); +      exception_handler_->SetClearException(clear_exception); +      if (found_dex_pc != DexFile::kDexNoIndex) { +        exception_handler_->SetHandlerMethod(method); +        exception_handler_->SetHandlerDexPc(found_dex_pc); +        exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc)); +        exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); +        return false;  // End stack walk. +      } +    } +    return true;  // Continue stack walk. +  } + +  Thread* const self_; +  // The exception we're looking for the catch block of. +  Handle<mirror::Throwable>* exception_; +  // The quick exception handler we're visiting for. +  QuickExceptionHandler* const exception_handler_; + +  DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor); +}; +  void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,                                        mirror::Throwable* exception) {    DCHECK(!is_deoptimization_); +  if (kDebugExceptionDelivery) { +    mirror::String* msg = exception->GetDetailMessage(); +    std::string str_msg(msg != nullptr ? msg->ToModifiedUtf8() : ""); +    self_->DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception) +                     << ": " << str_msg << "\n"); +  }    StackHandleScope<1> hs(self_);    Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception)); @@ -42,14 +122,14 @@ void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,    CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);    visitor.WalkStack(true); -  mirror::ArtMethod* catch_method = handler_quick_frame_->AsMirrorPtr();    if (kDebugExceptionDelivery) { -    if (catch_method == nullptr) { +    if (handler_quick_frame_->AsMirrorPtr() == nullptr) {        LOG(INFO) << "Handler is upcall"; -    } else { -      const DexFile& dex_file = *catch_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); -      int line_number = dex_file.GetLineNumFromPC(catch_method, handler_dex_pc_); -      LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")"; +    } +    if (handler_method_ != nullptr) { +      const DexFile& dex_file = *handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile(); +      int line_number = dex_file.GetLineNumFromPC(handler_method_, handler_dex_pc_); +      LOG(INFO) << "Handler: " << PrettyMethod(handler_method_) << " (line: " << line_number << ")";      }    }    if (clear_exception_) { @@ -62,12 +142,94 @@ void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,    // The debugger may suspend this thread and walk its stack. Let's do this before popping    // instrumentation frames.    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); -  instrumentation->ExceptionCaughtEvent(self_, throw_location, catch_method, handler_dex_pc_, +  instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,                                          exception_ref.Get());  } +// Prepares deoptimization. +class DeoptimizeStackVisitor FINAL : public StackVisitor { + public: +  DeoptimizeStackVisitor(Thread* self, Context* context, QuickExceptionHandler* exception_handler) +      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) +      : StackVisitor(self, context), self_(self), exception_handler_(exception_handler), +        prev_shadow_frame_(nullptr) { +    CHECK(!self_->HasDeoptimizationShadowFrame()); +  } + +  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    exception_handler_->SetHandlerFrameId(GetFrameId()); +    mirror::ArtMethod* method = GetMethod(); +    if (method == nullptr) { +      // This is the upcall, we remember the frame and last pc so that we may long jump to them. +      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc()); +      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); +      return false;  // End stack walk. +    } else if (method->IsRuntimeMethod()) { +      // Ignore callee save method. +      DCHECK(method->IsCalleeSaveMethod()); +      return true; +    } else { +      return HandleDeoptimization(method); +    } +  } + + private: +  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    MethodHelper mh(m); +    const DexFile::CodeItem* code_item = mh.GetCodeItem(); +    CHECK(code_item != nullptr); +    uint16_t num_regs = code_item->registers_size_; +    uint32_t dex_pc = GetDexPc(); +    const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc); +    uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits(); +    ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc); +    StackHandleScope<2> hs(self_); +    Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache())); +    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); +    verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, +                                      &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, +                                      m->GetAccessFlags(), false, true, true); +    verifier.Verify(); +    std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc); +    for (uint16_t reg = 0; reg < num_regs; ++reg) { +      VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2)); +      switch (kind) { +        case kUndefined: +          new_frame->SetVReg(reg, 0xEBADDE09); +          break; +        case kConstant: +          new_frame->SetVReg(reg, kinds.at((reg * 2) + 1)); +          break; +        case kReferenceVReg: +          new_frame->SetVRegReference(reg, +                                      reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind))); +          break; +        default: +          new_frame->SetVReg(reg, GetVReg(m, reg, kind)); +          break; +      } +    } +    if (prev_shadow_frame_ != nullptr) { +      prev_shadow_frame_->SetLink(new_frame); +    } else { +      self_->SetDeoptimizationShadowFrame(new_frame); +    } +    prev_shadow_frame_ = new_frame; +    return true; +  } + +  Thread* const self_; +  QuickExceptionHandler* const exception_handler_; +  ShadowFrame* prev_shadow_frame_; + +  DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor); +}; +  void QuickExceptionHandler::DeoptimizeStack() {    DCHECK(is_deoptimization_); +  if (kDebugExceptionDelivery) { +    self_->DumpStack(LOG(INFO) << "Deoptimizing: "); +  }    DeoptimizeStackVisitor visitor(self_, context_, this);    visitor.WalkStack(true); |