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/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index a4b579b..408ce69 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -814,13 +814,9 @@
       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     switch (type_) {
       case art::Primitive::kPrimNot: {
-        uint32_t ptr_val;
-        art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
-        ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
-        if (!visitor.SetVReg(method,
-                             static_cast<uint16_t>(slot_),
-                             ptr_val,
-                             art::kReferenceVReg)) {
+        if (!visitor.SetVRegReference(method,
+                                      static_cast<uint16_t>(slot_),
+                                      caller_->DecodeJObject(val_.l))) {
           return ERR(OPAQUE_FRAME);
         }
         break;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 8a1dbdd..c042d19 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2848,8 +2848,7 @@
         VLOG(jdwp) << tag << " object " << o << " is an invalid object";
         return JDWP::ERR_INVALID_OBJECT;
       }
-      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o.Ptr())),
-                                 kReferenceVReg)) {
+      if (!visitor.SetVRegReference(m, vreg, o)) {
         return FailSetLocalValue(visitor, vreg, tag, reinterpret_cast<uintptr_t>(o.Ptr()));
       }
       break;
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;
diff --git a/runtime/stack.h b/runtime/stack.h
index 1f305d2..4bc0fc8 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -22,6 +22,7 @@
 
 #include "base/locks.h"
 #include "base/macros.h"
+#include "obj_ptr.h"
 #include "quick/quick_method_frame_info.h"
 #include "stack_map.h"
 
@@ -236,6 +237,11 @@
 
   // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
   // is triggered to make the values effective.
+  bool SetVRegReference(ArtMethod* m, uint16_t vreg, ObjPtr<mirror::Object> new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
+  // is triggered to make the values effective.
   bool SetVRegPair(ArtMethod* m,
                    uint16_t vreg,
                    uint64_t new_value,
@@ -328,6 +334,9 @@
                                    uint64_t* val) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  ShadowFrame* PrepareSetVReg(ArtMethod* m, uint16_t vreg, bool wide)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   void SanityCheckFrame() const REQUIRES_SHARED(Locks::mutator_lock_);
 
   Thread* const thread_;