OSDN Git Service

Refactor exception handling for deoptimization
authorSebastien Hertz <shertz@google.com>
Wed, 23 Apr 2014 08:32:43 +0000 (10:32 +0200)
committerSebastien Hertz <shertz@google.com>
Fri, 25 Apr 2014 08:36:05 +0000 (10:36 +0200)
This CL refactors the exception handling (on the quick side) by isolating the
search of catch handler and the preparation of deoptimization.

We rename the CatchFinder class to QuickExceptionHandler so it's less specific
to catch handler search.

Finding catch handler happens in QuickExceptionHandler::FindCatch. Since the
CatchBlockStackVisitor resolves exception types, it may cause thread suspension
and breaks the assertion current thread can't be suspended. Therefore, we place
the exception in a SirtRef (while it is detached from the current thread) and
remove the thread suspension assertion.

Deoptimization now happens in QuickExceptionHandler::DeoptimizeStack. It uses
the new DeoptimizeStackVisitor class to create shadow frames.

We also add the Thread::GetDeoptimizationException method to get the definition
of the fake exception in only one place.

Change-Id: I01b19fa72af64329b5c3b6c7f0c3339d2d724978

runtime/Android.mk
runtime/catch_block_stack_visitor.cc
runtime/catch_block_stack_visitor.h
runtime/deoptimize_stack_visitor.cc [new file with mode: 0644]
runtime/deoptimize_stack_visitor.h [new file with mode: 0644]
runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
runtime/mirror/art_method.cc
runtime/quick_exception_handler.cc [moved from runtime/catch_finder.cc with 67% similarity]
runtime/quick_exception_handler.h [moved from runtime/catch_finder.h with 76% similarity]
runtime/thread.cc
runtime/thread.h

index d433fd5..bc971a9 100644 (file)
@@ -36,10 +36,10 @@ LIBART_COMMON_SRC_FILES := \
        base/unix_file/string_file.cc \
        check_jni.cc \
        catch_block_stack_visitor.cc \
-       catch_finder.cc \
        class_linker.cc \
        common_throws.cc \
        debugger.cc \
+       deoptimize_stack_visitor.cc \
        dex_file.cc \
        dex_file_verifier.cc \
        dex_instruction.cc \
@@ -129,6 +129,7 @@ LIBART_COMMON_SRC_FILES := \
        os_linux.cc \
        parsed_options.cc \
        primitive.cc \
+       quick_exception_handler.cc \
        quick/inline_method_analyser.cc \
        reference_table.cc \
        reflection.cc \
index 410fff9..8d10a97 100644 (file)
 #include "catch_block_stack_visitor.h"
 
 #include "dex_instruction.h"
-#include "catch_finder.h"
+#include "mirror/art_method-inl.h"
+#include "quick_exception_handler.h"
 #include "sirt_ref.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
 
 bool CatchBlockStackVisitor::VisitFrame() {
-  catch_finder_->SetHandlerFrameId(GetFrameId());
+  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.
-    catch_finder_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
-    catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+    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 if (is_deoptimization_) {
-      return HandleDeoptimization(method);
     } else {
       return HandleTryItems(method);
     }
@@ -46,68 +45,21 @@ bool CatchBlockStackVisitor::VisitFrame() {
 
 bool CatchBlockStackVisitor::HandleTryItems(mirror::ArtMethod* method) {
   uint32_t dex_pc = DexFile::kDexNoIndex;
-  if (method->IsNative()) {
-    ++native_method_count_;
-  } else {
+  if (!method->IsNative()) {
     dex_pc = GetDexPc();
   }
   if (dex_pc != DexFile::kDexNoIndex) {
     bool clear_exception = false;
-    SirtRef<mirror::Class> sirt_method_to_find(Thread::Current(), to_find_);
-    uint32_t found_dex_pc = method->FindCatchBlock(sirt_method_to_find, dex_pc, &clear_exception);
-    to_find_ = sirt_method_to_find.get();
-    catch_finder_->SetClearException(clear_exception);
+    uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception);
+    exception_handler_->SetClearException(clear_exception);
     if (found_dex_pc != DexFile::kDexNoIndex) {
-      catch_finder_->SetHandlerDexPc(found_dex_pc);
-      catch_finder_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
-      catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+      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.
 }
 
-bool CatchBlockStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) {
-  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);
-  SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
-  verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
-                                    &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
-                                    m->GetAccessFlags(), false, 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 {
-    catch_finder_->SetTopShadowFrame(new_frame);
-  }
-  prev_shadow_frame_ = new_frame;
-  return true;
-}
-
 }  // namespace art
index ce67e27..6f0fe11 100644 (file)
 #ifndef ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
 #define ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
 
-#include "mirror/throwable.h"
-#include "thread.h"
+#include "mirror/object-inl.h"
+#include "stack.h"
+#include "sirt_ref-inl.h"
 
 namespace art {
-class CatchFinder;
+
+namespace mirror {
+class Throwable;
+}  // namespace mirror
+class Context;
+class QuickExceptionHandler;
+class Thread;
 class ThrowLocation;
 
 // Finds catch handler or prepares deoptimization.
-class CatchBlockStackVisitor : public StackVisitor {
+class CatchBlockStackVisitor FINAL : public StackVisitor {
  public:
-  CatchBlockStackVisitor(Thread* self, Context* context, mirror::Throwable* exception,
-                         bool is_deoptimization, CatchFinder* catch_finder)
+  CatchBlockStackVisitor(Thread* self, Context* context, SirtRef<mirror::Throwable>& exception,
+                         QuickExceptionHandler* exception_handler)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(self, context),
-        self_(self), is_deoptimization_(is_deoptimization),
-        to_find_(is_deoptimization ? nullptr : exception->GetClass()),
-        catch_finder_(catch_finder), native_method_count_(0), prev_shadow_frame_(nullptr) {
+      : StackVisitor(self, context), self_(self), to_find_(self, exception->GetClass()),
+        exception_handler_(exception_handler) {
   }
 
-  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Thread* const self_;
-  const bool is_deoptimization_;
   // The type of the exception catch block to find.
-  mirror::Class* to_find_;
-  CatchFinder* const catch_finder_;
-  // Number of native methods passed in crawl (equates to number of SIRTs to pop)
-  uint32_t native_method_count_;
-  ShadowFrame* prev_shadow_frame_;
+  SirtRef<mirror::Class> to_find_;
+  QuickExceptionHandler* const exception_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
 };
diff --git a/runtime/deoptimize_stack_visitor.cc b/runtime/deoptimize_stack_visitor.cc
new file mode 100644 (file)
index 0000000..f2eaf00
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "deoptimize_stack_visitor.h"
+
+#include "mirror/art_method-inl.h"
+#include "object_utils.h"
+#include "quick_exception_handler.h"
+#include "sirt_ref-inl.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+bool DeoptimizeStackVisitor::VisitFrame() {
+  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);
+  }
+}
+
+bool DeoptimizeStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) {
+  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);
+  SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
+  SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
+  verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
+                                    &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
+                                    m->GetAccessFlags(), false, 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 {
+    exception_handler_->SetTopShadowFrame(new_frame);
+  }
+  prev_shadow_frame_ = new_frame;
+  return true;
+}
+
+}  // namespace art
diff --git a/runtime/deoptimize_stack_visitor.h b/runtime/deoptimize_stack_visitor.h
new file mode 100644 (file)
index 0000000..c898e7d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
+#define ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
+
+#include "base/mutex.h"
+#include "stack.h"
+
+namespace art {
+
+namespace mirror {
+class ArtMethod;
+}  // namespace mirror
+class QuickExceptionHandler;
+class Thread;
+
+// 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) {
+  }
+
+  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  Thread* const self_;
+  QuickExceptionHandler* const exception_handler_;
+  ShadowFrame* prev_shadow_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor);
+};
+
+}  // namespace art
+#endif  // ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
index 51c647a..6448045 100644 (file)
@@ -31,7 +31,7 @@ namespace art {
 extern "C" void artDeoptimize(Thread* self, mirror::ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
-  self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1));
+  self->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
   self->QuickDeliverException();
 }
 
index f3303a8..726004b 100644 (file)
@@ -315,13 +315,13 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue*
       } else {
         (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
       }
-      if (UNLIKELY(reinterpret_cast<intptr_t>(self->GetException(NULL)) == -1)) {
-        // Unusual case where we were running LLVM generated code and an
+      if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
+        // Unusual case where we were running generated code and an
         // exception was thrown to force the activations to be removed from the
         // stack. Continue execution in the interpreter.
         self->ClearException();
         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-        self->SetTopOfStack(NULL, 0);
+        self->SetTopOfStack(nullptr, 0);
         self->SetTopOfShadowStack(shadow_frame);
         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
       }
similarity index 67%
rename from runtime/catch_finder.cc
rename to runtime/quick_exception_handler.cc
index f0293d7..d5844b6 100644 (file)
  * limitations under the License.
  */
 
-#include "catch_finder.h"
+#include "quick_exception_handler.h"
+
 #include "catch_block_stack_visitor.h"
+#include "deoptimize_stack_visitor.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "sirt_ref-inl.h"
 
 namespace art {
 
-CatchFinder::CatchFinder(Thread* self, const ThrowLocation& throw_location,
-            mirror::Throwable* exception, bool is_deoptimization)
-  : self_(self), context_(self->GetLongJumpContext()),
-    exception_(exception), is_deoptimization_(is_deoptimization), throw_location_(throw_location),
+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), top_shadow_frame_(nullptr),
-                           handler_frame_id_(kInvalidFrameId) {
-  // Exception not in root sets, can't allow GC.
-  last_no_assert_suspension_cause_ = self->StartAssertNoThreadSuspension("Finding catch block");
+    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_dex_pc_(0),
+    clear_exception_(false), top_shadow_frame_(nullptr), handler_frame_id_(kInvalidFrameId) {
 }
 
-void CatchFinder::FindCatch() {
+void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
+                                      mirror::Throwable* exception) {
+  DCHECK(!is_deoptimization_);
+  SirtRef<mirror::Throwable> exception_ref(self_, exception);
+
   // Walk the stack to find catch handler or prepare for deoptimization.
-  CatchBlockStackVisitor visitor(self_, context_, exception_, is_deoptimization_, this);
+  CatchBlockStackVisitor visitor(self_, context_, exception_ref, this);
   visitor.WalkStack(true);
 
   mirror::ArtMethod* catch_method = *handler_quick_frame_;
-  if (catch_method == nullptr) {
-    if (kDebugExceptionDelivery) {
+  if (kDebugExceptionDelivery) {
+    if (catch_method == nullptr) {
       LOG(INFO) << "Handler is upcall";
-    }
-  } else {
-    CHECK(!is_deoptimization_);
-    if (kDebugExceptionDelivery) {
+    } 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 << ")";
@@ -55,17 +55,23 @@ void CatchFinder::FindCatch() {
     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.
-  if (!is_deoptimization_) {
-    // 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_,
-                                          exception_);
+    self_->SetException(ThrowLocation(), exception_ref.get());
   }
+  // 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_,
+                                        exception_ref.get());
+}
+
+void QuickExceptionHandler::DeoptimizeStack() {
+  DCHECK(is_deoptimization_);
+
+  DeoptimizeStackVisitor visitor(self_, context_, this);
+  visitor.WalkStack(true);
+
+  // Restore deoptimization exception
+  self_->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
 }
 
 // Unwinds all instrumentation stack frame prior to catch handler or upcall.
@@ -105,7 +111,7 @@ class InstrumentationStackVisitor : public StackVisitor {
   DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
 };
 
-void CatchFinder::UpdateInstrumentationStack() {
+void QuickExceptionHandler::UpdateInstrumentationStack() {
   if (method_tracing_active_) {
     InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_id_);
     visitor.WalkStack(true);
@@ -118,7 +124,7 @@ void CatchFinder::UpdateInstrumentationStack() {
   }
 }
 
-void CatchFinder::DoLongJump() {
+void QuickExceptionHandler::DoLongJump() {
   if (is_deoptimization_) {
     // TODO: proper return value.
     self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
similarity index 76%
rename from runtime/catch_finder.h
rename to runtime/quick_exception_handler.h
index ebbafe2..d06ce7c 100644 (file)
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_CATCH_FINDER_H_
-#define ART_RUNTIME_CATCH_FINDER_H_
+#ifndef ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
+#define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
 
-#include "mirror/art_method-inl.h"
-#include "thread.h"
+#include "base/logging.h"
+#include "base/mutex.h"
 
 namespace art {
 
+namespace mirror {
+class ArtMethod;
+class Throwable;
+}  // namespace mirror
+class Context;
+class Thread;
+class ThrowLocation;
+class ShadowFrame;
+
 static constexpr bool kDebugExceptionDelivery = false;
 static constexpr size_t kInvalidFrameId = 0xffffffff;
 
 // Manages exception delivery for Quick backend. Not used by Portable backend.
-class CatchFinder {
+class QuickExceptionHandler {
  public:
-  CatchFinder(Thread* self, const ThrowLocation& throw_location, mirror::Throwable* exception,
-              bool is_deoptimization)
+  QuickExceptionHandler(Thread* self, bool is_deoptimization)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ~CatchFinder() {
+  ~QuickExceptionHandler() {
     LOG(FATAL) << "UNREACHABLE";  // Expected to take long jump.
   }
 
-  void FindCatch() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void DeoptimizeStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -67,14 +77,9 @@ class CatchFinder {
  private:
   Thread* const self_;
   Context* const context_;
-  mirror::Throwable* const exception_;
   const bool is_deoptimization_;
-  // Location of the throw.
-  const ThrowLocation& throw_location_;
   // Is method tracing active?
   const bool method_tracing_active_;
-  // Support for nesting no thread suspension checks.
-  const char* last_no_assert_suspension_cause_;
   // Quick frame with found handler or last frame if no handler found.
   mirror::ArtMethod** handler_quick_frame_;
   // PC to branch to for the handler.
@@ -88,8 +93,8 @@ class CatchFinder {
   // Frame id of the catch handler or the upcall.
   size_t handler_frame_id_;
 
-  DISALLOW_COPY_AND_ASSIGN(CatchFinder);
+  DISALLOW_COPY_AND_ASSIGN(QuickExceptionHandler);
 };
 
 }  // namespace art
-#endif  // ART_RUNTIME_CATCH_FINDER_H_
+#endif  // ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
index 998579d..095404f 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "arch/context.h"
 #include "base/mutex.h"
-#include "catch_finder.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "cutils/atomic.h"
@@ -54,6 +53,7 @@
 #include "mirror/stack_trace_element.h"
 #include "monitor.h"
 #include "object_utils.h"
+#include "quick_exception_handler.h"
 #include "reflection.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -1841,7 +1841,7 @@ void Thread::QuickDeliverException() {
   // Don't leave exception visible while we try to find the handler, which may cause class
   // resolution.
   ClearException();
-  bool is_deoptimization = (exception == reinterpret_cast<mirror::Throwable*>(-1));
+  bool is_deoptimization = (exception == GetDeoptimizationException());
   if (kDebugExceptionDelivery) {
     if (!is_deoptimization) {
       mirror::String* msg = exception->GetDetailMessage();
@@ -1852,10 +1852,14 @@ void Thread::QuickDeliverException() {
       DumpStack(LOG(INFO) << "Deoptimizing: ");
     }
   }
-  CatchFinder catch_finder(this, throw_location, exception, is_deoptimization);
-  catch_finder.FindCatch();
-  catch_finder.UpdateInstrumentationStack();
-  catch_finder.DoLongJump();
+  QuickExceptionHandler exception_handler(this, is_deoptimization);
+  if (is_deoptimization) {
+    exception_handler.DeoptimizeStack();
+  } else {
+    exception_handler.FindCatch(throw_location, exception);
+  }
+  exception_handler.UpdateInstrumentationStack();
+  exception_handler.DoLongJump();
   LOG(FATAL) << "UNREACHABLE";
 }
 
@@ -2060,7 +2064,7 @@ void Thread::VisitRoots(RootCallback* visitor, void* arg) {
   if (tlsPtr_.opeer != nullptr) {
     visitor(&tlsPtr_.opeer, arg, thread_id, kRootThreadObject);
   }
-  if (tlsPtr_.exception != nullptr) {
+  if (tlsPtr_.exception != nullptr && tlsPtr_.exception != GetDeoptimizationException()) {
     visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg, thread_id, kRootNativeStack);
   }
   tlsPtr_.throw_location.VisitRoots(visitor, arg);
index d25bbe9..e5e4cae 100644 (file)
@@ -686,6 +686,11 @@ class Thread {
     return tlsPtr_.single_step_control;
   }
 
+  // Returns the fake exception used to activate deoptimization.
+  static mirror::Throwable* GetDeoptimizationException() {
+    return reinterpret_cast<mirror::Throwable*>(-1);
+  }
+
   void SetDeoptimizationShadowFrame(ShadowFrame* sf);
   void SetDeoptimizationReturnValue(const JValue& ret_val);