JVMTI PopFrame support

Implement support for the JVMTI can_pop_frames capability. This works
by marking shadow-frames with a bit that forces it to be popped or an
instruction to be retried. When a PopFrame is requested the plugin
will deoptimize the targeted thread and force the interpreter to deal
with the frame pop. If the can_pop_frames capability is enabled the
runtime will be forced to handle all exceptions through the
interpreter. This is required to support PopFrame during some
exception events.

Test: ./test.py --host
Test: ./art/tools/run-libjdwp-tests.sh --mode=host
Bug: 73255278
Bug: 111357976
Change-Id: I62d6b1f4ff387c794ba45093c3d6773aaf642067
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 2762629..c4b03b2 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -23,16 +23,39 @@
 #include "interpreter_common.h"
 #include "jit/jit.h"
 #include "jvalue-inl.h"
+#include "nth_caller_visitor.h"
 #include "safe_math.h"
 #include "shadow_frame-inl.h"
+#include "thread.h"
 
 namespace art {
 namespace interpreter {
 
+#define CHECK_FORCE_RETURN()                                                        \
+  do {                                                                              \
+    if (UNLIKELY(shadow_frame.GetForcePopFrame())) {                                \
+      DCHECK(PrevFrameWillRetry(self, shadow_frame))                                \
+          << "Pop frame forced without previous frame ready to retry instruction!"; \
+      DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());                     \
+      if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {                        \
+        SendMethodExitEvents(self,                                                  \
+                             instrumentation,                                       \
+                             shadow_frame,                                          \
+                             shadow_frame.GetThisObject(accessor.InsSize()),        \
+                             shadow_frame.GetMethod(),                              \
+                             inst->GetDexPc(insns),                                 \
+                             JValue());                                             \
+      }                                                                             \
+      ctx->result = JValue(); /* Handled in caller. */                              \
+      return;                                                                       \
+    }                                                                               \
+  } while (false)
+
 #define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr)                                    \
   do {                                                                                          \
     DCHECK(self->IsExceptionPending());                                                         \
     self->AllowThreadSuspension();                                                              \
+    CHECK_FORCE_RETURN();                                                                       \
     if (!MoveToExceptionHandler(self, shadow_frame, instr)) {                                   \
       /* Structured locking is to be enforced for abnormal termination, too. */                 \
       DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);                        \
@@ -43,6 +66,7 @@
       ctx->result = JValue(); /* Handled in caller. */                                          \
       return;                                                                                   \
     } else {                                                                                    \
+      CHECK_FORCE_RETURN();                                                                     \
       int32_t displacement =                                                                    \
           static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc);         \
       inst = inst->RelativeAt(displacement);                                                    \
@@ -51,8 +75,39 @@
 
 #define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation)
 
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, _next_function) \
+  do {                                                                                          \
+    if (UNLIKELY(shadow_frame.GetForceRetryInstruction())) {                                    \
+      /* Don't need to do anything except clear the flag and exception. We leave the */         \
+      /* instruction the same so it will be re-executed on the next go-around.       */         \
+      DCHECK(inst->IsInvoke());                                                                 \
+      shadow_frame.SetForceRetryInstruction(false);                                             \
+      if (UNLIKELY(_is_exception_pending)) {                                                    \
+        DCHECK(self->IsExceptionPending());                                                     \
+        if (kIsDebugBuild) {                                                                    \
+          LOG(WARNING) << "Suppressing exception for instruction-retry: "                       \
+                       << self->GetException()->Dump();                                         \
+        }                                                                                       \
+        self->ClearException();                                                                 \
+      }                                                                                         \
+    } else if (UNLIKELY(_is_exception_pending)) {                                               \
+      /* Should have succeeded. */                                                              \
+      DCHECK(!shadow_frame.GetForceRetryInstruction());                                         \
+      HANDLE_PENDING_EXCEPTION();                                                               \
+    } else {                                                                                    \
+      inst = inst->_next_function();                                                            \
+    }                                                                                           \
+  } while (false)
+
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(_is_exception_pending) \
+  POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_4xx)
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(_is_exception_pending) \
+  POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_3xx)
+
 #define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function)  \
   do {                                                                            \
+    /* Should only be on invoke instructions. */                                  \
+    DCHECK(!shadow_frame.GetForceRetryInstruction());                             \
     if (UNLIKELY(_is_exception_pending)) {                                        \
       HANDLE_PENDING_EXCEPTION();                                                 \
     } else {                                                                      \
@@ -66,17 +121,22 @@
   }
 
 // Code to run before each dex instruction.
-#define PREAMBLE_SAVE(save_ref)                                                                      \
+#define PREAMBLE_SAVE(save_ref)                                                                 \
   {                                                                                             \
-    if (UNLIKELY(instrumentation->HasDexPcListeners()) &&                                       \
-        UNLIKELY(!DoDexPcMoveEvent(self,                                                        \
-                                   accessor,                                                    \
-                                   shadow_frame,                                                \
-                                   dex_pc,                                                      \
-                                   instrumentation,                                             \
-                                   save_ref))) {                                                \
-      HANDLE_PENDING_EXCEPTION();                                                               \
-      break;                                                                                    \
+    /* We need to put this before & after the instrumentation to avoid having to put in a */    \
+    /* post-script macro.                                                                 */    \
+    CHECK_FORCE_RETURN();                                                                       \
+    if (UNLIKELY(instrumentation->HasDexPcListeners())) {                                       \
+      if (UNLIKELY(!DoDexPcMoveEvent(self,                                                      \
+                                     accessor,                                                  \
+                                     shadow_frame,                                              \
+                                     dex_pc,                                                    \
+                                     instrumentation,                                           \
+                                     save_ref))) {                                              \
+        HANDLE_PENDING_EXCEPTION();                                                             \
+        break;                                                                                  \
+      }                                                                                         \
+      CHECK_FORCE_RETURN();                                                                     \
     }                                                                                           \
   }                                                                                             \
   do {} while (false)
@@ -180,7 +240,8 @@
                                            const JValue& result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   bool had_event = false;
-  if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+  // We don't send method-exit if it's a pop-frame. We still send frame_popped though.
+  if (UNLIKELY(instrumentation->HasMethodExitListeners() && !frame.GetForcePopFrame())) {
     had_event = true;
     instrumentation->MethodExitEvent(self, thiz.Ptr(), method, dex_pc, result);
   }
@@ -217,6 +278,9 @@
   uint16_t inst_data;
   jit::Jit* jit = Runtime::Current()->GetJit();
 
+  DCHECK(!shadow_frame.GetForceRetryInstruction())
+      << "Entered interpreter from invoke without retry instruction being handled!";
+
   do {
     dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
@@ -1603,84 +1667,84 @@
         PREAMBLE();
         bool success = DoInvoke<kVirtual, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kVirtual, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_SUPER: {
         PREAMBLE();
         bool success = DoInvoke<kSuper, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_SUPER_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kSuper, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_DIRECT: {
         PREAMBLE();
         bool success = DoInvoke<kDirect, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_DIRECT_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kDirect, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_INTERFACE: {
         PREAMBLE();
         bool success = DoInvoke<kInterface, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_INTERFACE_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kInterface, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_STATIC: {
         PREAMBLE();
         bool success = DoInvoke<kStatic, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_STATIC_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kStatic, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_QUICK: {
         PREAMBLE();
         bool success = DoInvokeVirtualQuick<false>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
         PREAMBLE();
         bool success = DoInvokeVirtualQuick<true>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_POLYMORPHIC: {
@@ -1688,7 +1752,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokePolymorphic<false /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
         break;
       }
       case Instruction::INVOKE_POLYMORPHIC_RANGE: {
@@ -1696,7 +1760,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokePolymorphic<true /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
         break;
       }
       case Instruction::INVOKE_CUSTOM: {
@@ -1704,7 +1768,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokeCustom<false /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_CUSTOM_RANGE: {
@@ -1712,7 +1776,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokeCustom<true /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::NEG_INT: