Support deoptimization on exception

Allows to deoptimize when an exception is being thrown. We only
deoptimize if an executable frame (starting from the catch handler)
needs to be executed with the interpreter.

Before executing deoptimized frames, the exception is restored. The
interpreter starts by handling this exception at the point of the
throwing instruction.

Bug: 23714835
Change-Id: I0c5f7d4b257644acf12210aae8e5b6bb0f4af1f7
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 9d5ce9f..60defba 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -40,7 +40,7 @@
     handler_dex_pc_(0), clear_exception_(false), handler_frame_depth_(kInvalidFrameDepth) {
 }
 
-// Finds catch handler or prepares for deoptimization.
+// Finds catch handler.
 class CatchBlockStackVisitor FINAL : public StackVisitor {
  public:
   CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception,
@@ -125,7 +125,7 @@
   StackHandleScope<1> hs(self_);
   Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception));
 
-  // Walk the stack to find catch handler or prepare for deoptimization.
+  // Walk the stack to find catch handler.
   CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);
   visitor.WalkStack(true);
 
@@ -146,16 +146,6 @@
     // Put exception back in root set with clear throw location.
     self_->SetException(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();
-  if (instrumentation->HasExceptionCaughtListeners()
-      && self_->IsExceptionThrownByCurrentMethod(exception)) {
-    instrumentation->ExceptionCaughtEvent(self_, exception_ref.Get());
-    // Instrumentation may have been updated.
-    method_tracing_active_ = is_deoptimization_ ||
-        Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
-  }
 }
 
 // Prepares deoptimization.
@@ -189,6 +179,12 @@
       // Ignore callee save method.
       DCHECK(method->IsCalleeSaveMethod());
       return true;
+    } else if (method->IsNative()) {
+      // If we return from JNI with a pending exception and want to deoptimize, we need to skip
+      // the native method.
+      // The top method is a runtime method, the native method comes next.
+      CHECK_EQ(GetFrameDepth(), 1U);
+      return true;
     } else {
       return HandleDeoptimization(method);
     }
@@ -201,7 +197,7 @@
 
   bool HandleDeoptimization(ArtMethod* m) SHARED_REQUIRES(Locks::mutator_lock_) {
     const DexFile::CodeItem* code_item = m->GetCodeItem();
-    CHECK(code_item != nullptr);
+    CHECK(code_item != nullptr) << "No code item for " << PrettyMethod(m);
     uint16_t num_regs = code_item->registers_size_;
     uint32_t dex_pc = GetDexPc();
     StackHandleScope<2> hs(self_);  // Dex cache, class loader and method.