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/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);