Stack support for Optimizing compiler

Allows to read/write DEX registers from physical register or stack
location when the method is compiled with the Optimizing compiler.

Required fixing arm and arm64 JNI compiler by saving floating
point registers.

Bug: 18547544
Change-Id: I401579f251d1c0a130f6cf4a93a960cdcd7518f5
diff --git a/runtime/stack.cc b/runtime/stack.cc
index b39aebf..d570880 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -134,8 +134,7 @@
     } else {
       return cur_shadow_frame_->GetVRegReference(0);
     }
-  } else if (m->IsOptimized(GetInstructionSetPointerSize(
-      Runtime::Current()->GetInstructionSet()))) {
+  } else if (m->IsOptimized(sizeof(void*))) {
     // TODO: Implement, currently only used for exceptions when jdwp is enabled.
     UNIMPLEMENTED(WARNING)
         << "StackVisitor::GetThisObject is unimplemented with the optimizing compiler";
@@ -163,42 +162,10 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-    DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
-    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
-    uint32_t vmap_offset;
-    // TODO: IsInContext stops before spotting floating point registers.
-    if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
-      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
-      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
-      uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
-      if (!IsAccessibleRegister(reg, is_float)) {
-        return false;
-      }
-      uintptr_t ptr_val = GetRegister(reg, is_float);
-      bool target64 = Is64BitInstructionSet(kRuntimeISA);
-      if (target64) {
-        bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
-        bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
-        int64_t value_long = static_cast<int64_t>(ptr_val);
-        if (wide_lo) {
-          ptr_val = static_cast<uintptr_t>(value_long & 0xFFFFFFFF);
-        } else if (wide_hi) {
-          ptr_val = static_cast<uintptr_t>(value_long >> 32);
-        }
-      }
-      *val = ptr_val;
-      return true;
+    if (m->IsOptimized(sizeof(void*))) {
+      return GetVRegFromOptimizedCode(m, vreg, kind, val);
     } else {
-      const DexFile::CodeItem* code_item = m->GetCodeItem();
-      DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
-                                                        // its instructions?
-      uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
-                                   frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
-      DCHECK(addr != nullptr);
-      *val = *addr;
-      return true;
+      return GetVRegFromQuickCode(m, vreg, kind, val);
     }
   } else {
     DCHECK(cur_shadow_frame_ != nullptr);
@@ -207,6 +174,86 @@
   }
 }
 
+bool StackVisitor::GetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+                                        uint32_t* val) const {
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+  QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+  uint32_t vmap_offset;
+  // TODO: IsInContext stops before spotting floating point registers.
+  if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
+    bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+    uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+    uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
+    return GetRegisterIfAccessible(reg, kind, val);
+  } else {
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
+    DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                      // its instructions?
+    *val = *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+                        frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+    return true;
+  }
+}
+
+bool StackVisitor::GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+                                            uint32_t* val) const {
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
+  CodeInfo code_info = m->GetOptimizedCodeInfo();
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
+  DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                    // its instructions?
+  DCHECK_LT(vreg, code_item->registers_size_);
+  DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map,
+                                                                  code_item->registers_size_);
+  DexRegisterMap::LocationKind location_kind = dex_register_map.GetLocationKind(vreg);
+  switch (location_kind) {
+    case DexRegisterMap::kInStack: {
+      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+      const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
+      *val = *reinterpret_cast<const uint32_t*>(addr);
+      return true;
+    }
+    case DexRegisterMap::kInRegister:
+    case DexRegisterMap::kInFpuRegister: {
+      uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+      return GetRegisterIfAccessible(reg, kind, val);
+    }
+    case DexRegisterMap::kConstant:
+      *val = dex_register_map.GetConstant(vreg);
+      return true;
+    case DexRegisterMap::kNone:
+      return false;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const {
+  const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+  if (!IsAccessibleRegister(reg, is_float)) {
+    return false;
+  }
+  uintptr_t ptr_val = GetRegister(reg, is_float);
+  const bool target64 = Is64BitInstructionSet(kRuntimeISA);
+  if (target64) {
+    const bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
+    const bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
+    int64_t value_long = static_cast<int64_t>(ptr_val);
+    if (wide_lo) {
+      ptr_val = static_cast<uintptr_t>(Low32Bits(value_long));
+    } else if (wide_hi) {
+      ptr_val = static_cast<uintptr_t>(High32Bits(value_long));
+    }
+  }
+  *val = ptr_val;
+  return true;
+}
+
 bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
                                VRegKind kind_hi, uint64_t* val) const {
   if (kind_lo == kLongLoVReg) {
@@ -215,45 +262,15 @@
     DCHECK_EQ(kind_hi, kDoubleHiVReg);
   } else {
     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
+    UNREACHABLE();
   }
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-    DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
-    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
-    uint32_t vmap_offset_lo, vmap_offset_hi;
-    // TODO: IsInContext stops before spotting floating point registers.
-    if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
-        vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
-      bool is_float = (kind_lo == kDoubleLoVReg);
-      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
-      uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
-      uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
-      if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
-        return false;
-      }
-      uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float);
-      uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float);
-      bool target64 = Is64BitInstructionSet(kRuntimeISA);
-      if (target64) {
-        int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo);
-        int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi);
-        ptr_val_lo = static_cast<uintptr_t>(value_long_lo & 0xFFFFFFFF);
-        ptr_val_hi = static_cast<uintptr_t>(value_long_hi >> 32);
-      }
-      *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo);
-      return true;
+    if (m->IsOptimized(sizeof(void*))) {
+      return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val);
     } else {
-      const DexFile::CodeItem* code_item = m->GetCodeItem();
-      DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
-                                                        // its instructions?
-      uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
-                                   frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
-      DCHECK(addr != nullptr);
-      *val = *reinterpret_cast<uint64_t*>(addr);
-      return true;
+      return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val);
     }
   } else {
     DCHECK(cur_shadow_frame_ != nullptr);
@@ -262,61 +279,185 @@
   }
 }
 
+bool StackVisitor::GetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
+                                            VRegKind kind_hi, uint64_t* val) const {
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+  QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+  uint32_t vmap_offset_lo, vmap_offset_hi;
+  // TODO: IsInContext stops before spotting floating point registers.
+  if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
+      vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
+    bool is_float = (kind_lo == kDoubleLoVReg);
+    uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+    uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
+    uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
+    return GetRegisterPairIfAccessible(reg_lo, reg_hi, kind_lo, val);
+  } else {
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
+    DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                      // its instructions?
+    uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+                                 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+    *val = *reinterpret_cast<uint64_t*>(addr);
+    return true;
+  }
+}
+
+bool StackVisitor::GetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg,
+                                                VRegKind kind_lo, VRegKind kind_hi,
+                                                uint64_t* val) const {
+  uint32_t low_32bits;
+  uint32_t high_32bits;
+  bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, &low_32bits);
+  success &= GetVRegFromOptimizedCode(m, vreg + 1, kind_hi, &high_32bits);
+  if (success) {
+    *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits);
+  }
+  return success;
+}
+
+bool StackVisitor::GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi,
+                                               VRegKind kind_lo, uint64_t* val) const {
+  const bool is_float = (kind_lo == kDoubleLoVReg);
+  if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
+    return false;
+  }
+  uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float);
+  uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float);
+  bool target64 = Is64BitInstructionSet(kRuntimeISA);
+  if (target64) {
+    int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo);
+    int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi);
+    ptr_val_lo = static_cast<uintptr_t>(Low32Bits(value_long_lo));
+    ptr_val_hi = static_cast<uintptr_t>(High32Bits(value_long_hi));
+  }
+  *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo);
+  return true;
+}
+
 bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
                            VRegKind kind) {
   if (cur_quick_frame_ != nullptr) {
-    DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
-    DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-    DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
-    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
-    uint32_t vmap_offset;
-    // TODO: IsInContext stops before spotting floating point registers.
-    if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
-      bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
-      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
-      const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
-      if (!IsAccessibleRegister(reg, is_float)) {
-        return false;
+      DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
+      DCHECK(m == GetMethod());
+      if (m->IsOptimized(sizeof(void*))) {
+        return SetVRegFromOptimizedCode(m, vreg, new_value, kind);
+      } else {
+        return SetVRegFromQuickCode(m, vreg, new_value, kind);
       }
-      bool target64 = Is64BitInstructionSet(kRuntimeISA);
-      // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
-      if (target64) {
-        bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
-        bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
-        if (wide_lo || wide_hi) {
-          uintptr_t old_reg_val = GetRegister(reg, is_float);
-          uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
-          uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
-          uint64_t mask = 0xffffffff;
-          if (wide_lo) {
-            mask = mask << 32;
-          } else {
-            new_vreg_portion = new_vreg_portion << 32;
-          }
-          new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
-        }
-      }
-      SetRegister(reg, new_value, is_float);
-      return true;
     } else {
-      const DexFile::CodeItem* code_item = m->GetCodeItem();
-      DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
-                                                        // its instructions?
-      uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
-                                   frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
-      DCHECK(addr != nullptr);
-      *addr = new_value;
+      cur_shadow_frame_->SetVReg(vreg, new_value);
       return true;
     }
+}
+
+bool StackVisitor::SetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+                                        VRegKind kind) {
+  DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
+  DCHECK(m == GetMethod());
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+  QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+  uint32_t vmap_offset;
+  // TODO: IsInContext stops before spotting floating point registers.
+  if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
+    bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+    uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+    uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
+    return SetRegisterIfAccessible(reg, new_value, kind);
   } else {
-    DCHECK(cur_shadow_frame_ != nullptr);
-    cur_shadow_frame_->SetVReg(vreg, new_value);
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
+    DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                      // its instructions?
+    uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+                                 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+    *addr = new_value;
     return true;
   }
 }
 
+bool StackVisitor::SetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+                                            VRegKind kind) {
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
+  CodeInfo code_info = m->GetOptimizedCodeInfo();
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
+  DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                    // its instructions?
+  DCHECK_LT(vreg, code_item->registers_size_);
+  DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map,
+                                                                  code_item->registers_size_);
+  DexRegisterMap::LocationKind location_kind = dex_register_map.GetLocationKind(vreg);
+  uint32_t dex_pc = m->ToDexPc(cur_quick_frame_pc_, false);
+  switch (location_kind) {
+    case DexRegisterMap::kInStack: {
+      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+      uint8_t* addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + offset;
+      *reinterpret_cast<uint32_t*>(addr) = new_value;
+      return true;
+    }
+    case DexRegisterMap::kInRegister:
+    case DexRegisterMap::kInFpuRegister: {
+      uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+      return SetRegisterIfAccessible(reg, new_value, kind);
+    }
+    case DexRegisterMap::kConstant:
+      LOG(ERROR) << StringPrintf("Cannot change value of DEX register v%u used as a constant at "
+                                 "DEX pc 0x%x (native pc 0x%x) of method %s",
+                                 vreg, dex_pc, native_pc_offset,
+                                 PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+      return false;
+    case DexRegisterMap::kNone:
+      LOG(ERROR) << StringPrintf("No location for DEX register v%u at DEX pc 0x%x "
+                                 "(native pc 0x%x) of method %s",
+                                 vreg, dex_pc, native_pc_offset,
+                                 PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+      return false;
+    default:
+      LOG(FATAL) << StringPrintf("Unknown location for DEX register v%u at DEX pc 0x%x "
+                                 "(native pc 0x%x) of method %s",
+                                 vreg, dex_pc, native_pc_offset,
+                                 PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+      UNREACHABLE();
+  }
+}
+
+bool StackVisitor::SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind) {
+  const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+  if (!IsAccessibleRegister(reg, is_float)) {
+    return false;
+  }
+  const bool target64 = Is64BitInstructionSet(kRuntimeISA);
+
+  // Create a new value that can hold both low 32 and high 32 bits, in
+  // case we are running 64 bits.
+  uintptr_t full_new_value = new_value;
+  // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
+  if (target64) {
+    bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
+    bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
+    if (wide_lo || wide_hi) {
+      uintptr_t old_reg_val = GetRegister(reg, is_float);
+      uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
+      uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
+      uint64_t mask = 0xffffffff;
+      if (wide_lo) {
+        mask = mask << 32;
+      } else {
+        new_vreg_portion = new_vreg_portion << 32;
+      }
+      full_new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
+    }
+  }
+  SetRegister(reg, full_new_value, is_float);
+  return true;
+}
+
 bool StackVisitor::SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
                                VRegKind kind_lo, VRegKind kind_hi) {
   if (kind_lo == kLongLoVReg) {
@@ -329,49 +470,10 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-    DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
-    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
-    uint32_t vmap_offset_lo, vmap_offset_hi;
-    // TODO: IsInContext stops before spotting floating point registers.
-    if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
-        vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
-      bool is_float = (kind_lo == kDoubleLoVReg);
-      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
-      uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
-      uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
-      if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
-        return false;
-      }
-      uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF);
-      uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32);
-      bool target64 = Is64BitInstructionSet(kRuntimeISA);
-      // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
-      if (target64) {
-        uintptr_t old_reg_val_lo = GetRegister(reg_lo, is_float);
-        uintptr_t old_reg_val_hi = GetRegister(reg_hi, is_float);
-        uint64_t new_vreg_portion_lo = static_cast<uint64_t>(new_value_lo);
-        uint64_t new_vreg_portion_hi = static_cast<uint64_t>(new_value_hi) << 32;
-        uint64_t old_reg_val_lo_as_wide = static_cast<uint64_t>(old_reg_val_lo);
-        uint64_t old_reg_val_hi_as_wide = static_cast<uint64_t>(old_reg_val_hi);
-        uint64_t mask_lo = static_cast<uint64_t>(0xffffffff) << 32;
-        uint64_t mask_hi = 0xffffffff;
-        new_value_lo = static_cast<uintptr_t>((old_reg_val_lo_as_wide & mask_lo) | new_vreg_portion_lo);
-        new_value_hi = static_cast<uintptr_t>((old_reg_val_hi_as_wide & mask_hi) | new_vreg_portion_hi);
-      }
-      SetRegister(reg_lo, new_value_lo, is_float);
-      SetRegister(reg_hi, new_value_hi, is_float);
-      return true;
+    if (m->IsOptimized(sizeof(void*))) {
+      return SetVRegPairFromOptimizedCode(m, vreg, new_value, kind_lo, kind_hi);
     } else {
-      const DexFile::CodeItem* code_item = m->GetCodeItem();
-      DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
-                                                        // its instructions?
-      uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
-                                   frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
-      DCHECK(addr != nullptr);
-      *reinterpret_cast<uint64_t*>(addr) = new_value;
-      return true;
+      return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi);
     }
   } else {
     DCHECK(cur_shadow_frame_ != nullptr);
@@ -380,6 +482,60 @@
   }
 }
 
+bool StackVisitor::SetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+                                            VRegKind kind_lo, VRegKind kind_hi) {
+  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+  QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+  uint32_t vmap_offset_lo, vmap_offset_hi;
+  // TODO: IsInContext stops before spotting floating point registers.
+  if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
+      vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
+    bool is_float = (kind_lo == kDoubleLoVReg);
+    uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+    uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
+    uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
+    return SetRegisterPairIfAccessible(reg_lo, reg_hi, new_value, is_float);
+  } else {
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
+    DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
+                                                      // its instructions?
+    uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+                                 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+    *reinterpret_cast<uint64_t*>(addr) = new_value;
+    return true;
+  }
+}
+
+bool StackVisitor::SetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+                                                VRegKind kind_lo, VRegKind kind_hi) {
+  uint32_t low_32bits = Low32Bits(new_value);
+  uint32_t high_32bits = High32Bits(new_value);
+  bool success = SetVRegFromOptimizedCode(m, vreg, low_32bits, kind_lo);
+  success &= SetVRegFromOptimizedCode(m, vreg + 1, high_32bits, kind_hi);
+  return success;
+}
+
+bool StackVisitor::SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi,
+                                               uint64_t new_value, bool is_float) {
+  if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
+    return false;
+  }
+  uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF);
+  uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32);
+  bool target64 = Is64BitInstructionSet(kRuntimeISA);
+  // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
+  if (target64) {
+    DCHECK_EQ(reg_lo, reg_hi);
+    SetRegister(reg_lo, new_value, is_float);
+  } else {
+    SetRegister(reg_lo, new_value_lo, is_float);
+    SetRegister(reg_hi, new_value_hi, is_float);
+  }
+  return true;
+}
+
 bool StackVisitor::IsAccessibleGPR(uint32_t reg) const {
   DCHECK(context_ != nullptr);
   return context_->IsAccessibleGPR(reg);