Add StackVisitor::SetVRegReference().

Avoid converting ObjPtr<>s to uint32_t and back.

Test: m test-art-host-gtest
Test: testrunner.py --host --interpreter
Test: run-jdwp-tests.sh --mode=host --variant=X64
Test: run-jdwp-tests.sh --mode=host --variant=X64 --debug
Bug: 31113334
Change-Id: I4e5c1577930de58772b35179aa4281ae4bbca300
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 80a563b..2ea3949 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -38,6 +38,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
 #include "quick/quick_method_frame_info.h"
 #include "runtime.h"
 #include "thread.h"
@@ -372,13 +373,10 @@
   return true;
 }
 
-bool StackVisitor::SetVReg(ArtMethod* m,
-                           uint16_t vreg,
-                           uint32_t new_value,
-                           VRegKind kind) {
+ShadowFrame* StackVisitor::PrepareSetVReg(ArtMethod* m, uint16_t vreg, bool wide) {
   CodeItemDataAccessor accessor(m->DexInstructionData());
   if (!accessor.HasCodeItem()) {
-    return false;
+    return nullptr;
   }
   ShadowFrame* shadow_frame = GetCurrentShadowFrame();
   if (shadow_frame == nullptr) {
@@ -388,15 +386,32 @@
     const uint16_t num_regs = accessor.RegistersSize();
     shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
     CHECK(shadow_frame != nullptr);
-    // Remember the vreg has been set for debugging and must not be overwritten by the
+    // Remember the vreg(s) has been set for debugging and must not be overwritten by the
     // original value during deoptimization of the stack.
     thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true;
+    if (wide) {
+      thread_->GetUpdatedVRegFlags(frame_id)[vreg + 1] = true;
+    }
   }
-  if (kind == kReferenceVReg) {
-    shadow_frame->SetVRegReference(vreg, reinterpret_cast<mirror::Object*>(new_value));
-  } else {
-    shadow_frame->SetVReg(vreg, new_value);
+  return shadow_frame;
+}
+
+bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind) {
+  DCHECK(kind == kIntVReg || kind == kFloatVReg);
+  ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ false);
+  if (shadow_frame == nullptr) {
+    return false;
   }
+  shadow_frame->SetVReg(vreg, new_value);
+  return true;
+}
+
+bool StackVisitor::SetVRegReference(ArtMethod* m, uint16_t vreg, ObjPtr<mirror::Object> new_value) {
+  ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ false);
+  if (shadow_frame == nullptr) {
+    return false;
+  }
+  shadow_frame->SetVRegReference(vreg, new_value);
   return true;
 }
 
@@ -413,21 +428,9 @@
     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
     UNREACHABLE();
   }
-  CodeItemDataAccessor accessor(m->DexInstructionData());
-  if (!accessor.HasCodeItem()) {
-    return false;
-  }
-  ShadowFrame* shadow_frame = GetCurrentShadowFrame();
+  ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ true);
   if (shadow_frame == nullptr) {
-    // This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger).
-    const size_t frame_id = GetFrameId();
-    const uint16_t num_regs = accessor.RegistersSize();
-    shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
-    CHECK(shadow_frame != nullptr);
-    // Remember the vreg pair has been set for debugging and must not be overwritten by the
-    // original value during deoptimization of the stack.
-    thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true;
-    thread_->GetUpdatedVRegFlags(frame_id)[vreg + 1] = true;
+    return false;
   }
   shadow_frame->SetVRegLong(vreg, new_value);
   return true;