Refactor exception handling for deoptimization

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
diff --git a/runtime/catch_block_stack_visitor.cc b/runtime/catch_block_stack_visitor.cc
index 410fff9..8d10a97 100644
--- a/runtime/catch_block_stack_visitor.cc
+++ b/runtime/catch_block_stack_visitor.cc
@@ -17,27 +17,26 @@
 #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::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