Add fast path for exception vreg copying.

It is not necessary to decode CodeInfo in GetVReg
since the caller already did it.

Test: ./art/test.py -b --host --64 --interpreter
Change-Id: I0f8941f43acdc0f2c43b78ef87d3e796e320c959
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 1777b3d..727bdf0 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -325,10 +325,12 @@
     // Get vreg value from its current location.
     uint32_t vreg_value;
     VRegKind vreg_kind = ToVRegKind(throw_vreg_map[vreg].GetKind());
-    bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(),
-                                                   vreg,
-                                                   vreg_kind,
-                                                   &vreg_value);
+    bool get_vreg_success =
+        stack_visitor->GetVReg(stack_visitor->GetMethod(),
+                               vreg,
+                               vreg_kind,
+                               &vreg_value,
+                               throw_vreg_map[vreg]);
     CHECK(get_vreg_success) << "VReg " << vreg << " was optimized out ("
                             << "method=" << ArtMethod::PrettyMethod(stack_visitor->GetMethod())
                             << ", dex_pc=" << stack_visitor->GetDexPc() << ", "
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 3fc6fd1..6d1e384 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -201,7 +201,11 @@
   return false;
 }
 
-bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const {
+bool StackVisitor::GetVReg(ArtMethod* m,
+                           uint16_t vreg,
+                           VRegKind kind,
+                           uint32_t* val,
+                           std::optional<DexRegisterLocation> location) const {
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
     DCHECK(m == GetMethod());
@@ -210,6 +214,16 @@
       return true;
     }
     DCHECK(cur_oat_quick_method_header_->IsOptimized());
+    if (location.has_value() && kind != kReferenceVReg) {
+      uint32_t val2 = *val;
+      // The caller already known the register location, so we can use the faster overload
+      // which does not decode the stack maps.
+      bool ok = GetVRegFromOptimizedCode(location.value(), kind, val);
+      // Compare to the slower overload.
+      DCHECK_EQ(ok, GetVRegFromOptimizedCode(m, vreg, kind, &val2));
+      DCHECK_EQ(*val, val2);
+      return ok;
+    }
     return GetVRegFromOptimizedCode(m, vreg, kind, val);
   } else {
     DCHECK(cur_shadow_frame_ != nullptr);
@@ -290,6 +304,32 @@
   }
 }
 
+bool StackVisitor::GetVRegFromOptimizedCode(DexRegisterLocation location,
+                                            VRegKind kind,
+                                            uint32_t* val) const {
+  switch (location.GetKind()) {
+    case DexRegisterLocation::Kind::kInvalid:
+      break;
+    case DexRegisterLocation::Kind::kInStack: {
+      const uint8_t* sp = reinterpret_cast<const uint8_t*>(cur_quick_frame_);
+      *val = *reinterpret_cast<const uint32_t*>(sp + location.GetStackOffsetInBytes());
+      return true;
+    }
+    case DexRegisterLocation::Kind::kInRegister:
+    case DexRegisterLocation::Kind::kInRegisterHigh:
+    case DexRegisterLocation::Kind::kInFpuRegister:
+    case DexRegisterLocation::Kind::kInFpuRegisterHigh:
+      return GetRegisterIfAccessible(location.GetMachineRegister(), kind, val);
+    case DexRegisterLocation::Kind::kConstant:
+      *val = location.GetConstant();
+      return true;
+    case DexRegisterLocation::Kind::kNone:
+      return false;
+  }
+  LOG(FATAL) << "Unexpected location kind " << location.GetKind();
+  UNREACHABLE();
+}
+
 bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const {
   const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
 
diff --git a/runtime/stack.h b/runtime/stack.h
index aa741df..ad73e75 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -17,6 +17,7 @@
 #ifndef ART_RUNTIME_STACK_H_
 #define ART_RUNTIME_STACK_H_
 
+#include <optional>
 #include <stdint.h>
 #include <string>
 
@@ -223,7 +224,12 @@
   bool GetNextMethodAndDexPc(ArtMethod** next_method, uint32_t* next_dex_pc)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const
+  bool GetVReg(ArtMethod* m,
+               uint16_t vreg,
+               VRegKind kind,
+               uint32_t* val,
+               std::optional<DexRegisterLocation> location =
+                   std::optional<DexRegisterLocation>()) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   bool GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi,
@@ -330,6 +336,8 @@
                                     VRegKind kind_lo, VRegKind kind_hi,
                                     uint64_t* val) const
       REQUIRES_SHARED(Locks::mutator_lock_);
+  bool GetVRegFromOptimizedCode(DexRegisterLocation location, VRegKind kind, uint32_t* val) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
   bool GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, VRegKind kind_lo,
                                    uint64_t* val) const
       REQUIRES_SHARED(Locks::mutator_lock_);