Add "kind" argument to Get/SetVReg.

In order to determine where a register is promoted its necessary to know
the kind of use of the register.
Extend notion of precise-ness to numeric verifier register types.
Dump verifier output in oatdump.
Dump vregs with their location or constant value.
Introduce indenting ostream utility.

Change-Id: Ia3d29497877976bc24465484743bca08236e1768
diff --git a/src/stack.h b/src/stack.h
index fd2fd15..5b5609c 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -29,12 +29,27 @@
 namespace art {
 
 class AbstractMethod;
+class Context;
 class Object;
 class ShadowFrame;
 class StackIndirectReferenceTable;
 class ScopedObjectAccess;
 class Thread;
 
+// The kind of vreg being accessed in calls to Set/GetVReg.
+enum VRegKind {
+  kReferenceVReg,
+  kIntVReg,
+  kFloatVReg,
+  kLongLoVReg,
+  kLongHiVReg,
+  kDoubleLoVReg,
+  kDoubleHiVReg,
+  kConstant,
+  kImpreciseConstant,
+  kUndefined,
+};
+
 class ShadowFrame {
  public:
   static ShadowFrame* Create(uint16_t num_refs, uint16_t num_vregs, ShadowFrame* link,
@@ -366,15 +381,17 @@
     return num_frames_;
   }
 
-  uint32_t GetVReg(AbstractMethod* m, int vreg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  uint32_t GetVReg(AbstractMethod* m, uint16_t vreg, VRegKind kind) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetVReg(AbstractMethod* m, int vreg, uint32_t new_value)
+  void SetVReg(AbstractMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uintptr_t GetGPR(uint32_t reg) const;
 
   uint32_t GetVReg(AbstractMethod** cur_quick_frame, const DexFile::CodeItem* code_item,
-                   uint32_t core_spills, uint32_t fp_spills, size_t frame_size, int vreg) const {
+                   uint32_t core_spills, uint32_t fp_spills, size_t frame_size,
+                   uint16_t vreg) const {
     int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
     DCHECK_EQ(cur_quick_frame, GetCurrentQuickFrame());
     byte* vreg_addr = reinterpret_cast<byte*>(cur_quick_frame) + offset;
@@ -482,6 +499,77 @@
   Context* const context_;
 };
 
+class VmapTable {
+ public:
+  explicit VmapTable(const uint16_t* table) : table_(table) {
+  }
+
+  uint16_t operator[](size_t i) const {
+    return table_[i + 1];
+  }
+
+  size_t size() const {
+    return table_[0];
+  }
+
+  // Is the dex register 'vreg' in the context or on the stack? Should not be called when the
+  // 'kind' is unknown or constant.
+  bool IsInContext(size_t vreg, uint32_t& vmap_offset, VRegKind kind) const {
+    DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
+           kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
+           kind == kDoubleHiVReg || kind == kImpreciseConstant);
+    vmap_offset = 0xEBAD0FF5;
+    // TODO: take advantage of the registers being ordered
+    // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
+    //       are never promoted to floating point registers.
+    bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+    bool in_floats = false;
+    for (size_t i = 0; i < size(); ++i) {
+      // Stop if we find what we are are looking for.
+      if ((table_[i + 1] == vreg) && (in_floats == is_float)) {
+        vmap_offset = i;
+        return true;
+      }
+      // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers.
+      if (table_[i + 1] == 0xffff) {
+        in_floats = true;
+      }
+    }
+    return false;
+  }
+
+  // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed
+  // by IsInContext above). If the kind is floating point then the result will be a floating point
+  // register number, otherwise it will be an integer register number.
+  uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const {
+    // Compute the register we need to load from the context.
+    DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
+           kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
+           kind == kDoubleHiVReg || kind == kImpreciseConstant);
+    // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
+    //       are never promoted to floating point registers.
+    bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+    uint32_t matches = 0;
+    if (is_float) {
+      while (table_[matches] != 0xffff) {
+        matches++;
+      }
+    }
+    CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
+    uint32_t spill_shifts = 0;
+    while (matches != (vmap_offset + 1)) {
+      DCHECK_NE(spill_mask, 0u);
+      matches += spill_mask & 1;  // Add 1 if the low bit is set
+      spill_mask >>= 1;
+      spill_shifts++;
+    }
+    spill_shifts--;  // wind back one as we want the last match
+    return spill_shifts;
+  }
+ private:
+  const uint16_t* table_;
+};
+
 }  // namespace art
 
 #endif  // ART_SRC_STACK_H_