Display optimizing compiler's CodeInfo objects in oatdump.

A few elements are not displayed yet (stack mask, inline info) though.

Change-Id: I5e51a801c580169abc5d1ef43ad581aadc110754
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bf3ed14..033308c 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -620,7 +620,7 @@
     Location location = locations->GetEnvironmentAt(i);
     switch (location.GetKind()) {
       case Location::kConstant: {
-        DCHECK(current == location.GetConstant());
+        DCHECK_EQ(current, location.GetConstant());
         if (current->IsLongConstant()) {
           int64_t value = current->AsLongConstant()->GetValue();
           stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, Low32Bits(value));
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 3974e53..5283d5d 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -166,18 +166,23 @@
         stack_map.SetStackMask(*entry.sp_mask);
       }
 
-      // Set the register map.
-      MemoryRegion register_region = dex_register_maps_region.Subregion(
-          next_dex_register_map_offset,
-          DexRegisterMap::kFixedSize + entry.num_dex_registers * DexRegisterMap::SingleEntrySize());
-      next_dex_register_map_offset += register_region.size();
-      DexRegisterMap dex_register_map(register_region);
-      stack_map.SetDexRegisterMapOffset(register_region.start() - memory_start);
+      if (entry.num_dex_registers != 0) {
+        // Set the register map.
+        MemoryRegion register_region = dex_register_maps_region.Subregion(
+            next_dex_register_map_offset,
+            DexRegisterMap::kFixedSize
+            + entry.num_dex_registers * DexRegisterMap::SingleEntrySize());
+        next_dex_register_map_offset += register_region.size();
+        DexRegisterMap dex_register_map(register_region);
+        stack_map.SetDexRegisterMapOffset(register_region.start() - memory_start);
 
-      for (size_t j = 0; j < entry.num_dex_registers; ++j) {
-        DexRegisterEntry register_entry =
-            dex_register_maps_.Get(j + entry.dex_register_maps_start_index);
-        dex_register_map.SetRegisterInfo(j, register_entry.kind, register_entry.value);
+        for (size_t j = 0; j < entry.num_dex_registers; ++j) {
+          DexRegisterEntry register_entry =
+              dex_register_maps_.Get(j + entry.dex_register_maps_start_index);
+          dex_register_map.SetRegisterInfo(j, register_entry.kind, register_entry.value);
+        }
+      } else {
+        stack_map.SetDexRegisterMapOffset(StackMap::kNoDexRegisterMap);
       }
 
       // Set the inlining info.
@@ -196,7 +201,7 @@
           inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
         }
       } else {
-        stack_map.SetInlineDescriptorOffset(InlineInfo::kNoInlineInfo);
+        stack_map.SetInlineDescriptorOffset(StackMap::kNoInlineInfo);
       }
     }
   }
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 5ee6ae0..744fb45 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -61,6 +61,7 @@
   MemoryRegion stack_mask = stack_map.GetStackMask();
   ASSERT_TRUE(SameBits(stack_mask, sp_mask));
 
+  ASSERT_TRUE(stack_map.HasDexRegisterMap());
   DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2);
   ASSERT_EQ(DexRegisterMap::kInStack, dex_registers.GetLocationKind(0));
   ASSERT_EQ(DexRegisterMap::kConstant, dex_registers.GetLocationKind(1));
@@ -107,6 +108,7 @@
   MemoryRegion stack_mask = stack_map.GetStackMask();
   ASSERT_TRUE(SameBits(stack_mask, sp_mask1));
 
+  ASSERT_TRUE(stack_map.HasDexRegisterMap());
   DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2);
   ASSERT_EQ(DexRegisterMap::kInStack, dex_registers.GetLocationKind(0));
   ASSERT_EQ(DexRegisterMap::kConstant, dex_registers.GetLocationKind(1));
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 931cca7..11ccafb 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -764,7 +764,7 @@
                                     oat_method.GetVmapTableOffsetOffset());
         success = false;
       } else if (options_->dump_vmap_) {
-        DumpVmap(*indent2_os, oat_method);
+        DumpVmapData(*indent2_os, oat_method, code_item);
       }
     }
     {
@@ -869,39 +869,89 @@
     os << ")";
   }
 
-  void DumpVmap(std::ostream& os, const OatFile::OatMethod& oat_method) {
-    // If the native GC map is null, then this method has been compiled with the
-    // optimizing compiler. The optimizing compiler currently outputs its stack map
-    // in the vmap table, and the code below does not work with such a stack map.
+  // Display data stored at the the vmap offset of an oat method.
+  void DumpVmapData(std::ostream& os,
+                    const OatFile::OatMethod& oat_method,
+                    const DexFile::CodeItem* code_item) {
     if (oat_method.GetGcMap() == nullptr) {
-      return;
+      // If the native GC map is null, then this method has been
+      // compiled with the optimizing compiler. The optimizing
+      // compiler currently outputs its stack maps in the vmap table.
+      const void* raw_code_info = oat_method.GetVmapTable();
+      if (raw_code_info != nullptr) {
+        CodeInfo code_info(raw_code_info);
+        DCHECK(code_item != nullptr);
+        DumpCodeInfo(os, code_info, *code_item);
+      }
+    } else {
+      // Otherwise, display the vmap table.
+      const uint8_t* raw_table = oat_method.GetVmapTable();
+      if (raw_table != nullptr) {
+        VmapTable vmap_table(raw_table);
+        DumpVmapTable(os, oat_method, vmap_table);
+      }
     }
-    const uint8_t* raw_table = oat_method.GetVmapTable();
-    if (raw_table != nullptr) {
-      const VmapTable vmap_table(raw_table);
-      bool first = true;
-      bool processing_fp = false;
-      uint32_t spill_mask = oat_method.GetCoreSpillMask();
-      for (size_t i = 0; i < vmap_table.Size(); i++) {
-        uint16_t dex_reg = vmap_table[i];
-        uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i,
-                                                      processing_fp ? kFloatVReg : kIntVReg);
-        os << (first ? "v" : ", v")  << dex_reg;
-        if (!processing_fp) {
-          os << "/r" << cpu_reg;
-        } else {
-          os << "/fr" << cpu_reg;
-        }
-        first = false;
-        if (!processing_fp && dex_reg == 0xFFFF) {
-          processing_fp = true;
-          spill_mask = oat_method.GetFpSpillMask();
+  }
+
+  // Display a CodeInfo object emitted by the optimizing compiler.
+  void DumpCodeInfo(std::ostream& os,
+                    const CodeInfo& code_info,
+                    const DexFile::CodeItem& code_item) {
+    uint16_t number_of_dex_registers = code_item.registers_size_;
+    uint32_t code_info_size = code_info.GetOverallSize();
+    size_t number_of_stack_maps = code_info.GetNumberOfStackMaps();
+    os << "  Optimized CodeInfo (size=" << code_info_size
+       << ", number_of_dex_registers=" << number_of_dex_registers
+       << ", number_of_stack_maps=" << number_of_stack_maps << ")\n";
+    for (size_t i = 0; i < number_of_stack_maps; ++i) {
+      StackMap stack_map = code_info.GetStackMapAt(i);
+      // TODO: Display stack_mask value.
+      os << "    StackMap " << i
+         << std::hex
+         << " (dex_pc=0x" << stack_map.GetDexPc()
+         << ", native_pc_offset=0x" << stack_map.GetNativePcOffset()
+         << ", register_mask=0x" << stack_map.GetRegisterMask()
+         << std::dec
+         << ")\n";
+      if (stack_map.HasDexRegisterMap()) {
+        DexRegisterMap dex_register_map =
+            code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+        for (size_t j = 0; j < number_of_dex_registers; ++j) {
+          os << "      v" << j << ": "
+             << DexRegisterMap::PrettyDescriptor(dex_register_map.GetLocationKind(j))
+             << " (" << dex_register_map.GetValue(j) << ")\n";
         }
       }
-      os << "\n";
+      // TODO: Display more information from code_info.
     }
   }
 
+  // Display a vmap table.
+  void DumpVmapTable(std::ostream& os,
+                     const OatFile::OatMethod& oat_method,
+                     const VmapTable& vmap_table) {
+    bool first = true;
+    bool processing_fp = false;
+    uint32_t spill_mask = oat_method.GetCoreSpillMask();
+    for (size_t i = 0; i < vmap_table.Size(); i++) {
+      uint16_t dex_reg = vmap_table[i];
+      uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i,
+                                                    processing_fp ? kFloatVReg : kIntVReg);
+      os << (first ? "v" : ", v")  << dex_reg;
+      if (!processing_fp) {
+        os << "/r" << cpu_reg;
+      } else {
+        os << "/fr" << cpu_reg;
+      }
+      first = false;
+      if (!processing_fp && dex_reg == 0xFFFF) {
+        processing_fp = true;
+        spill_mask = oat_method.GetFpSpillMask();
+      }
+    }
+    os << "\n";
+  }
+
   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
                          const DexFile::CodeItem* code_item) {
     if (code_item != nullptr) {
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 7cc3e57..fd22361 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -61,8 +61,6 @@
   static constexpr int kDepthOffset = 0;
   static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
 
-  static constexpr uint32_t kNoInlineInfo = -1;
-
   MemoryRegion region_;
 
   friend class CodeInfo;
@@ -76,10 +74,11 @@
  * [location_kind, register_value]+.
  *
  * The location_kind for a Dex register can either be:
- * - Constant: register_value holds the constant,
- * - Stack: register_value holds the stack offset,
- * - Register: register_value holds the physical register number.
- * - None: the register has no location yet, meaning it has not been set.
+ * - kConstant: register_value holds the constant,
+ * - kStack: register_value holds the stack offset,
+ * - kRegister: register_value holds the physical register number.
+ * - kFpuRegister: register_value holds the physical register number.
+ * - kNone: the register has no location yet, meaning it has not been set.
  */
 class DexRegisterMap {
  public:
@@ -93,6 +92,24 @@
     kConstant
   };
 
+  static const char* PrettyDescriptor(LocationKind kind) {
+    switch (kind) {
+      case kNone:
+        return "none";
+      case kInStack:
+        return "in stack";
+      case kInRegister:
+        return "in register";
+      case kInFpuRegister:
+        return "in fpu register";
+      case kConstant:
+        return "as constant";
+      default:
+        LOG(FATAL) << "Invalid location kind " << static_cast<int>(kind);
+        return nullptr;
+    }
+  }
+
   LocationKind GetLocationKind(uint16_t register_index) const {
     return region_.Load<LocationKind>(
         kFixedSize + register_index * SingleEntrySize());
@@ -191,11 +208,15 @@
     }
   }
 
-  bool HasInlineInfo() const {
-    return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
+  bool HasDexRegisterMap() const {
+    return GetDexRegisterMapOffset() != kNoDexRegisterMap;
   }
 
-  bool Equals(const StackMap& other) {
+  bool HasInlineInfo() const {
+    return GetInlineDescriptorOffset() != kNoInlineInfo;
+  }
+
+  bool Equals(const StackMap& other) const {
     return region_.pointer() == other.region_.pointer()
        && region_.size() == other.region_.size();
   }
@@ -205,6 +226,14 @@
     return RoundUp(StackMap::kFixedSize + stack_mask_size, 4);
   }
 
+  // Special (invalid) offset for the DexRegisterMapOffset field meaning
+  // that there is no Dex register map for this stack map.
+  static constexpr uint32_t kNoDexRegisterMap = -1;
+
+  // Special (invalid) offset for the InlineDescriptorOffset field meaning
+  // that there is no inline info for this stack map.
+  static constexpr uint32_t kNoInlineInfo = -1;
+
  private:
   static constexpr int kDexPcOffset = 0;
   static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
@@ -271,20 +300,22 @@
     return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
   }
 
-  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
+  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
+    DCHECK(stack_map.HasDexRegisterMap());
     uint32_t offset = stack_map.GetDexRegisterMapOffset();
     return DexRegisterMap(region_.Subregion(offset,
         DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
   }
 
-  InlineInfo GetInlineInfoOf(StackMap stack_map) {
+  InlineInfo GetInlineInfoOf(StackMap stack_map) const {
+    DCHECK(stack_map.HasInlineInfo());
     uint32_t offset = stack_map.GetInlineDescriptorOffset();
     uint8_t depth = region_.Load<uint8_t>(offset);
     return InlineInfo(region_.Subregion(offset,
         InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
   }
 
-  StackMap GetStackMapForDexPc(uint32_t dex_pc) {
+  StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
       StackMap stack_map = GetStackMapAt(i);
       if (stack_map.GetDexPc() == dex_pc) {
@@ -295,7 +326,7 @@
     UNREACHABLE();
   }
 
-  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
+  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
     // TODO: stack maps are sorted by native pc, we can do a binary search.
     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
       StackMap stack_map = GetStackMapAt(i);