Move some helper methods to DexRegisterLocation.

Test: test-art-host-gtest-stack_map_test
Change-Id: I0abab008159db023d531df69214cd3bb8c0639bd
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 777a1fc..1168798 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -47,6 +47,7 @@
         "debug_print.cc",
         "debugger.cc",
         "dex/dex_file_annotations.cc",
+        "dex_register_location.cc",
         "dex_to_dex_decompiler.cc",
         "elf_file.cc",
         "exec_utils.cc",
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 8a2a70e..8f9f45c 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -75,7 +75,7 @@
     for (int i = 0; i < number_of_references; ++i) {
       int reg = registers[i];
       CHECK_LT(reg, accessor.RegistersSize());
-      DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(reg);
+      DexRegisterLocation location = dex_register_map[reg];
       switch (location.GetKind()) {
         case DexRegisterLocation::Kind::kNone:
           // Not set, should not be a reference.
@@ -98,7 +98,7 @@
           CHECK_EQ(location.GetValue(), 0);
           break;
         default:
-          LOG(FATAL) << "Unexpected location kind " << location.GetInternalKind();
+          LOG(FATAL) << "Unexpected location kind " << location.GetKind();
       }
     }
   }
diff --git a/runtime/dex_register_location.cc b/runtime/dex_register_location.cc
new file mode 100644
index 0000000..f3b0973
--- /dev/null
+++ b/runtime/dex_register_location.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_register_location.h"
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) {
+  return stream << "Kind<" <<  static_cast<int32_t>(kind) << ">";
+}
+
+std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) {
+  using Kind = DexRegisterLocation::Kind;
+  switch (reg.GetKind()) {
+    case Kind::kInvalid:
+      return stream << "Invalid";
+    case Kind::kNone:
+      return stream << "None";
+    case Kind::kInStack:
+      return stream << "sp+" << reg.GetValue();
+    case Kind::kInRegister:
+      return stream << "r" << reg.GetValue();
+    case Kind::kInRegisterHigh:
+      return stream << "r" << reg.GetValue() << "/hi";
+    case Kind::kInFpuRegister:
+      return stream << "f" << reg.GetValue();
+    case Kind::kInFpuRegisterHigh:
+      return stream << "f" << reg.GetValue() << "/hi";
+    case Kind::kConstant:
+      return stream << "#" << reg.GetValue();
+    default:
+      return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind())
+                    << "," << reg.GetValue() << ")";
+  }
+}
+
+}  // namespace art
diff --git a/runtime/dex_register_location.h b/runtime/dex_register_location.h
index a20dccb..98b4d41 100644
--- a/runtime/dex_register_location.h
+++ b/runtime/dex_register_location.h
@@ -48,9 +48,6 @@
 
   Kind GetKind() const { return kind_; }
 
-  // TODO: Remove.
-  Kind GetInternalKind() const { return kind_; }
-
   int32_t GetValue() const { return value_; }
 
   bool operator==(DexRegisterLocation other) const {
@@ -61,6 +58,24 @@
     return !(*this == other);
   }
 
+  int32_t GetStackOffsetInBytes() const {
+    DCHECK(kind_ == Kind::kInStack);
+    return value_;
+  }
+
+  int32_t GetConstant() const {
+    DCHECK(kind_ == Kind::kConstant);
+    return value_;
+  }
+
+  int32_t GetMachineRegister() const {
+    DCHECK(kind_ == Kind::kInRegister ||
+           kind_ == Kind::kInRegisterHigh ||
+           kind_ == Kind::kInFpuRegister ||
+           kind_ == Kind::kInFpuRegisterHigh);
+    return value_;
+  }
+
  private:
   DexRegisterLocation() {}
 
@@ -70,9 +85,8 @@
   friend class DexRegisterMap;  // Allow creation of uninitialized array of locations.
 };
 
-static inline std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) {
-  return stream << "Kind<" <<  static_cast<int32_t>(kind) << ">";
-}
+std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind);
+std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
 
 }  // namespace art
 
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 0a8e0cd..5e73603 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -515,7 +515,7 @@
     } else {
       DCHECK_EQ(vreg_map.size(), number_of_vregs);
       for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) {
-        DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg);
+        DexRegisterLocation::Kind location = vreg_map[vreg].GetKind();
         if (location == DexRegisterLocation::Kind::kNone) {
           // Dex register is dead or uninitialized.
           continue;
@@ -529,7 +529,7 @@
         DCHECK_EQ(location, DexRegisterLocation::Kind::kInStack);
 
         int32_t vreg_value = shadow_frame->GetVReg(vreg);
-        int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg);
+        int32_t slot_offset = vreg_map[vreg].GetStackOffsetInBytes();
         DCHECK_LT(slot_offset, static_cast<int32_t>(frame_size));
         DCHECK_GT(slot_offset, 0);
         (reinterpret_cast<int32_t*>(memory))[slot_offset / sizeof(int32_t)] = vreg_value;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index cf1cbe7..8b99b9f 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -245,7 +245,7 @@
 
   // Copy values between them.
   for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) {
-    DexRegisterLocation::Kind catch_location = catch_vreg_map.GetLocationKind(vreg);
+    DexRegisterLocation::Kind catch_location = catch_vreg_map[vreg].GetKind();
     if (catch_location == DexRegisterLocation::Kind::kNone) {
       continue;
     }
@@ -253,7 +253,7 @@
 
     // Get vreg value from its current location.
     uint32_t vreg_value;
-    VRegKind vreg_kind = ToVRegKind(throw_vreg_map.GetLocationKind(vreg));
+    VRegKind vreg_kind = ToVRegKind(throw_vreg_map[vreg].GetKind());
     bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(),
                                                    vreg,
                                                    vreg_kind,
@@ -264,7 +264,7 @@
                             << "native_pc_offset=" << stack_visitor->GetNativePcOffset() << ")";
 
     // Copy value to the catch phi's stack slot.
-    int32_t slot_offset = catch_vreg_map.GetStackOffsetInBytes(vreg);
+    int32_t slot_offset = catch_vreg_map[vreg].GetStackOffsetInBytes();
     ArtMethod** frame_top = stack_visitor->GetCurrentQuickFrame();
     uint8_t* slot_address = reinterpret_cast<uint8_t*>(frame_top) + slot_offset;
     uint32_t* slot_ptr = reinterpret_cast<uint32_t*>(slot_address);
@@ -417,14 +417,14 @@
         continue;
       }
 
-      DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg);
+      DexRegisterLocation::Kind location = vreg_map[vreg].GetKind();
       static constexpr uint32_t kDeadValue = 0xEBADDE09;
       uint32_t value = kDeadValue;
       bool is_reference = false;
 
       switch (location) {
         case DexRegisterLocation::Kind::kInStack: {
-          const int32_t offset = vreg_map.GetStackOffsetInBytes(vreg);
+          const int32_t offset = vreg_map[vreg].GetStackOffsetInBytes();
           const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset;
           value = *reinterpret_cast<const uint32_t*>(addr);
           uint32_t bit = (offset >> 2);
@@ -437,7 +437,7 @@
         case DexRegisterLocation::Kind::kInRegisterHigh:
         case DexRegisterLocation::Kind::kInFpuRegister:
         case DexRegisterLocation::Kind::kInFpuRegisterHigh: {
-          uint32_t reg = vreg_map.GetMachineRegister(vreg);
+          uint32_t reg = vreg_map[vreg].GetMachineRegister();
           bool result = GetRegisterIfAccessible(reg, ToVRegKind(location), &value);
           CHECK(result);
           if (location == DexRegisterLocation::Kind::kInRegister) {
@@ -448,7 +448,7 @@
           break;
         }
         case DexRegisterLocation::Kind::kConstant: {
-          value = vreg_map.GetConstant(vreg);
+          value = vreg_map[vreg].GetConstant();
           if (value == 0) {
             // Make it a reference for extra safety.
             is_reference = true;
@@ -459,9 +459,7 @@
           break;
         }
         default: {
-          LOG(FATAL)
-              << "Unexpected location kind "
-              << vreg_map.GetLocationInternalKind(vreg);
+          LOG(FATAL) << "Unexpected location kind " << vreg_map[vreg].GetKind();
           UNREACHABLE();
         }
       }
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 56e47b9..2188cdc 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -242,10 +242,10 @@
     return false;
   }
   DCHECK_EQ(dex_register_map.size(), number_of_dex_registers);
-  DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg);
+  DexRegisterLocation::Kind location_kind = dex_register_map[vreg].GetKind();
   switch (location_kind) {
     case DexRegisterLocation::Kind::kInStack: {
-      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+      const int32_t offset = dex_register_map[vreg].GetStackOffsetInBytes();
       const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
       *val = *reinterpret_cast<const uint32_t*>(addr);
       return true;
@@ -254,18 +254,16 @@
     case DexRegisterLocation::Kind::kInRegisterHigh:
     case DexRegisterLocation::Kind::kInFpuRegister:
     case DexRegisterLocation::Kind::kInFpuRegisterHigh: {
-      uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+      uint32_t reg = dex_register_map[vreg].GetMachineRegister();
       return GetRegisterIfAccessible(reg, kind, val);
     }
     case DexRegisterLocation::Kind::kConstant:
-      *val = dex_register_map.GetConstant(vreg);
+      *val = dex_register_map[vreg].GetConstant();
       return true;
     case DexRegisterLocation::Kind::kNone:
       return false;
     default:
-      LOG(FATAL)
-          << "Unexpected location kind "
-          << dex_register_map.GetLocationInternalKind(vreg);
+      LOG(FATAL) << "Unexpected location kind " << dex_register_map[vreg].GetKind();
       UNREACHABLE();
   }
 }
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 23cc1d6..43609e8 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -89,31 +89,6 @@
   }
 }
 
-std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) {
-  using Kind = DexRegisterLocation::Kind;
-  switch (reg.GetKind()) {
-    case Kind::kNone:
-      return stream << "None";
-    case Kind::kInStack:
-      return stream << "sp+" << reg.GetValue();
-    case Kind::kInRegister:
-      return stream << "r" << reg.GetValue();
-    case Kind::kInRegisterHigh:
-      return stream << "r" << reg.GetValue() << "/hi";
-    case Kind::kInFpuRegister:
-      return stream << "f" << reg.GetValue();
-    case Kind::kInFpuRegisterHigh:
-      return stream << "f" << reg.GetValue() << "/hi";
-    case Kind::kConstant:
-      return stream << "#" << reg.GetValue();
-    case Kind::kInvalid:
-      return stream << "Invalid";
-    default:
-      return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind())
-                    << "," << reg.GetValue() << ")";
-  }
-}
-
 template<typename Accessor>
 static void AddTableSizeStats(const char* table_name,
                               const BitTable<Accessor::kCount>& table,
@@ -144,13 +119,13 @@
   AddTableSizeStats<DexRegisterInfo>("DexRegisterCatalog", dex_register_catalog_, stats);
 }
 
-static void DumpDexRegisterMap(VariableIndentationOutputStream* vios,
-                               const DexRegisterMap& map) {
-  if (map.HasAnyLiveDexRegisters()) {
+void DexRegisterMap::Dump(VariableIndentationOutputStream* vios) const {
+  if (HasAnyLiveDexRegisters()) {
     ScopedIndentation indent1(vios);
-    for (size_t i = 0; i < map.size(); ++i) {
-      if (map.IsDexRegisterLive(i)) {
-        vios->Stream() << "v" << i << ":" << map.Get(i) << " ";
+    for (size_t i = 0; i < size(); ++i) {
+      DexRegisterLocation reg = (*this)[i];
+      if (reg.IsLive()) {
+        vios->Stream() << "v" << i << ":" << reg << " ";
       }
     }
     vios->Stream() << "\n";
@@ -240,7 +215,7 @@
     vios->Stream() << stack_mask.LoadBit(e - i - 1);
   }
   vios->Stream() << ")\n";
-  DumpDexRegisterMap(vios, code_info.GetDexRegisterMapOf(*this));
+  code_info.GetDexRegisterMapOf(*this).Dump(vios);
   uint32_t depth = code_info.GetInlineDepthOf(*this);
   for (size_t d = 0; d < depth; d++) {
     InlineInfo inline_info = code_info.GetInlineInfoAtDepth(*this, d);
@@ -267,7 +242,7 @@
         << ", method_index=" << GetMethodIndex(method_info);
   }
   vios->Stream() << ")\n";
-  DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(depth, stack_map));
+  code_info.GetDexRegisterMapAtDepth(depth, stack_map).Dump(vios);
 }
 
 }  // namespace art
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index ea358c6..aa19f09 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -54,9 +54,11 @@
 // Information on Dex register locations for a specific PC.
 // Effectively just a convenience wrapper for DexRegisterLocation vector.
 // If the size is small enough, it keeps the data on the stack.
+// TODO: Replace this with generic purpose "small-vector" implementation.
 class DexRegisterMap {
  public:
   using iterator = DexRegisterLocation*;
+  using const_iterator = const DexRegisterLocation*;
 
   // Create map for given number of registers and initialize them to the given value.
   DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
@@ -70,76 +72,36 @@
   DexRegisterLocation* data() {
     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
   }
+  const DexRegisterLocation* data() const {
+    return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
+  }
 
   iterator begin() { return data(); }
   iterator end() { return data() + count_; }
-
+  const_iterator begin() const { return data(); }
+  const_iterator end() const { return data() + count_; }
   size_t size() const { return count_; }
-
   bool empty() const { return count_ == 0; }
 
-  DexRegisterLocation Get(size_t index) const {
+  DexRegisterLocation& operator[](size_t index) {
     DCHECK_LT(index, count_);
-    return count_ <= kSmallCount ? regs_small_[index] : regs_large_[index];
+    return data()[index];
   }
-
-  DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number) const {
-    return Get(dex_register_number).GetKind();
-  }
-
-  // TODO: Remove.
-  DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number) const {
-    return Get(dex_register_number).GetKind();
-  }
-
-  DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number) const {
-    return Get(dex_register_number);
-  }
-
-  int32_t GetStackOffsetInBytes(uint16_t dex_register_number) const {
-    DexRegisterLocation location = Get(dex_register_number);
-    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
-    return location.GetValue();
-  }
-
-  int32_t GetConstant(uint16_t dex_register_number) const {
-    DexRegisterLocation location = Get(dex_register_number);
-    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
-    return location.GetValue();
-  }
-
-  int32_t GetMachineRegister(uint16_t dex_register_number) const {
-    DexRegisterLocation location = Get(dex_register_number);
-    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInRegister ||
-           location.GetKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
-           location.GetKind() == DexRegisterLocation::Kind::kInFpuRegister ||
-           location.GetKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh);
-    return location.GetValue();
-  }
-
-  ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const {
-    return Get(dex_register_number).IsLive();
+  const DexRegisterLocation& operator[](size_t index) const {
+    DCHECK_LT(index, count_);
+    return data()[index];
   }
 
   size_t GetNumberOfLiveDexRegisters() const {
-    size_t number_of_live_dex_registers = 0;
-    for (size_t i = 0; i < count_; ++i) {
-      if (IsDexRegisterLive(i)) {
-        ++number_of_live_dex_registers;
-      }
-    }
-    return number_of_live_dex_registers;
+    return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
   }
 
   bool HasAnyLiveDexRegisters() const {
-    for (size_t i = 0; i < count_; ++i) {
-      if (IsDexRegisterLive(i)) {
-        return true;
-      }
-    }
-    return false;
+    return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
   }
 
+  void Dump(VariableIndentationOutputStream* vios) const;
+
  private:
   // Store the data inline if the number of registers is small to avoid memory allocations.
   // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 4a53425..7a7a80e 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3658,7 +3658,7 @@
           REQUIRES_SHARED(Locks::mutator_lock_) {
         bool found = false;
         for (size_t dex_reg = 0; dex_reg != number_of_dex_registers; ++dex_reg) {
-          DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(dex_reg);
+          DexRegisterLocation location = dex_register_map[dex_reg];
           if (location.GetKind() == kind && static_cast<size_t>(location.GetValue()) == index) {
             visitor(ref, dex_reg, stack_visitor);
             found = true;