Show stack maps and Dex register maps in oatdump's assembly code.

Stack maps and Dex register maps are not longer displayed
in CodeInfo sections, unless `--dump:code_info_stack_maps'
is passed to oatdump.

Change-Id: Id82adb406d7e56cda27df8e5a8bd328a88b9ee11
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 04f5a6a..0c3061a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -304,6 +304,7 @@
   OatDumperOptions(bool dump_raw_mapping_table,
                    bool dump_raw_gc_map,
                    bool dump_vmap,
+                   bool dump_code_info_stack_maps,
                    bool disassemble_code,
                    bool absolute_addresses,
                    const char* class_filter,
@@ -315,6 +316,7 @@
     : dump_raw_mapping_table_(dump_raw_mapping_table),
       dump_raw_gc_map_(dump_raw_gc_map),
       dump_vmap_(dump_vmap),
+      dump_code_info_stack_maps_(dump_code_info_stack_maps),
       disassemble_code_(disassemble_code),
       absolute_addresses_(absolute_addresses),
       class_filter_(class_filter),
@@ -328,6 +330,7 @@
   const bool dump_raw_mapping_table_;
   const bool dump_raw_gc_map_;
   const bool dump_vmap_;
+  const bool dump_code_info_stack_maps_;
   const bool disassemble_code_;
   const bool absolute_addresses_;
   const char* const class_filter_;
@@ -1011,15 +1014,13 @@
   void DumpVmapData(std::ostream& os,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem* code_item) {
-    if (oat_method.GetGcMap() == nullptr) {
-      // 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.
+    if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+      // The optimizing compiler outputs its CodeInfo data 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);
+        DumpCodeInfo(os, code_info, oat_method, *code_item);
       }
     } else {
       // Otherwise, display the vmap table.
@@ -1034,8 +1035,12 @@
   // Display a CodeInfo object emitted by the optimizing compiler.
   void DumpCodeInfo(std::ostream& os,
                     const CodeInfo& code_info,
+                    const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem& code_item) {
-    code_info.Dump(os, code_item.registers_size_, true);
+    code_info.Dump(os,
+                   oat_method.GetCodeOffset(),
+                   code_item.registers_size_,
+                   options_.dump_code_info_stack_maps_);
   }
 
   // Display a vmap table.
@@ -1198,6 +1203,23 @@
     }
   }
 
+  uint32_t DumpInformationAtOffset(std::ostream& os,
+                                   const OatFile::OatMethod& oat_method,
+                                   const DexFile::CodeItem* code_item,
+                                   size_t offset,
+                                   bool suspend_point_mapping) {
+    if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+      if (suspend_point_mapping) {
+        DumpDexRegisterMapAtOffset(os, oat_method, code_item, offset);
+      }
+      // The return value is not used in the case of a method compiled
+      // with the optimizing compiler.
+      return DexFile::kDexNoIndex;
+    } else {
+      return DumpMappingAtOffset(os, oat_method, offset, suspend_point_mapping);
+    }
+  }
+
   uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
                                size_t offset, bool suspend_point_mapping) {
     MappingTable table(oat_method.GetMappingTable());
@@ -1300,6 +1322,35 @@
     }
   }
 
+  // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
+  // the optimizing compiler?
+  static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
+                                                    const DexFile::CodeItem* code_item) {
+    // If the native GC map is null and the Dex `code_item` is not
+    // null, then this method has been compiled with the optimizing
+    // compiler.
+    return oat_method.GetGcMap() == nullptr && code_item != nullptr;
+  }
+
+  void DumpDexRegisterMapAtOffset(std::ostream& os,
+                                  const OatFile::OatMethod& oat_method,
+                                  const DexFile::CodeItem* code_item,
+                                  size_t offset) {
+    // This method is only relevant for oat methods compiled with the
+    // optimizing compiler.
+    DCHECK(IsMethodGeneratedByOptimizingCompiler(oat_method, code_item));
+
+    // The optimizing compiler outputs its CodeInfo data in the vmap table.
+    const void* raw_code_info = oat_method.GetVmapTable();
+    if (raw_code_info != nullptr) {
+      CodeInfo code_info(raw_code_info);
+      StackMap stack_map = code_info.GetStackMapForNativePcOffset(offset);
+      if (stack_map.IsValid()) {
+        stack_map.Dump(os, code_info, oat_method.GetCodeOffset(), code_item->registers_size_);
+      }
+    }
+  }
+
   verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
                                          const DexFile* dex_file,
                                          const DexFile::ClassDef& class_def,
@@ -1338,11 +1389,11 @@
       size_t offset = 0;
       while (offset < code_size) {
         if (!bad_input) {
-          DumpMappingAtOffset(os, oat_method, offset, false);
+          DumpInformationAtOffset(os, oat_method, code_item, offset, false);
         }
         offset += disassembler_->Dump(os, quick_native_pc + offset);
         if (!bad_input) {
-          uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
+          uint32_t dex_pc = DumpInformationAtOffset(os, oat_method, code_item, offset, true);
           if (dex_pc != DexFile::kDexNoIndex) {
             DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
             if (verifier != nullptr) {
@@ -2229,6 +2280,8 @@
       dump_raw_gc_map_ = true;
     } else if (option == "--no-dump:vmap") {
       dump_vmap_ = false;
+    } else if (option =="--dump:code_info_stack_maps") {
+      dump_code_info_stack_maps_ = true;
     } else if (option == "--no-disassemble") {
       disassemble_code_ = false;
     } else if (option.starts_with("--symbolize=")) {
@@ -2308,6 +2361,9 @@
         "  --no-dump:vmap may be used to disable vmap dumping.\n"
         "      Example: --no-dump:vmap\n"
         "\n"
+        "  --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
+        "      Example: --dump:code_info_stack_maps\n"
+        "\n"
         "  --no-disassemble may be used to disable disassembly.\n"
         "      Example: --no-disassemble\n"
         "\n"
@@ -2348,6 +2404,7 @@
   bool dump_raw_mapping_table_ = false;
   bool dump_raw_gc_map_ = false;
   bool dump_vmap_ = true;
+  bool dump_code_info_stack_maps_ = false;
   bool disassemble_code_ = true;
   bool symbolize_ = false;
   bool list_classes_ = false;
@@ -2367,6 +2424,7 @@
         args_->dump_raw_mapping_table_,
         args_->dump_raw_gc_map_,
         args_->dump_vmap_,
+        args_->dump_code_info_stack_maps_,
         args_->disassemble_code_,
         absolute_addresses,
         args_->class_filter_,
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index c36ee05..a64071f 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -212,38 +212,8 @@
               << " (" << location.GetValue() << ")" << suffix << '\n';
 }
 
-void CodeInfo::DumpStackMap(std::ostream& os,
-                            size_t stack_map_num,
-                            uint16_t number_of_dex_registers) const {
-  StackMap stack_map = GetStackMapAt(stack_map_num);
-  DumpStackMapHeader(os, stack_map_num);
-  if (stack_map.HasDexRegisterMap(*this)) {
-    DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-    dex_register_map.Dump(os, *this, number_of_dex_registers);
-  }
-}
-
-void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
-  StackMap stack_map = GetStackMapAt(stack_map_num);
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "StackMap " << stack_map_num
-              << std::hex
-              << " (dex_pc=0x" << stack_map.GetDexPc(*this)
-              << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
-              << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
-              << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
-              << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
-              << std::dec
-              << ", stack_mask=0b";
-  MemoryRegion stack_mask = stack_map.GetStackMask(*this);
-  for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    indented_os << stack_mask.LoadBit(e - i - 1);
-  }
-  indented_os << ")\n";
-};
-
 void CodeInfo::Dump(std::ostream& os,
+                    uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     bool dump_stack_maps) const {
   uint32_t code_info_size = GetOverallSize();
@@ -265,7 +235,9 @@
   // Display stack maps along with (live) Dex register maps.
   if (dump_stack_maps) {
     for (size_t i = 0; i < number_of_stack_maps; ++i) {
-      DumpStackMap(indented_os, i, number_of_dex_registers);
+      StackMap stack_map = GetStackMapAt(i);
+      stack_map.Dump(
+          indented_os, *this, code_offset, number_of_dex_registers, " " + std::to_string(i));
     }
   }
   // TODO: Dump the stack map's inline information? We need to know more from the caller:
@@ -307,6 +279,34 @@
   }
 }
 
+void StackMap::Dump(std::ostream& os,
+                    const CodeInfo& code_info,
+                    uint32_t code_offset,
+                    uint16_t number_of_dex_registers,
+                    const std::string& header_suffix) const {
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indented_os(&indent_filter);
+  indented_os << "StackMap" << header_suffix
+              << std::hex
+              << " [native_pc=0x" << code_offset + GetNativePcOffset(code_info) << "]"
+              << " (dex_pc=0x" << GetDexPc(code_info)
+              << ", native_pc_offset=0x" << GetNativePcOffset(code_info)
+              << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(code_info)
+              << ", inline_info_offset=0x" << GetInlineDescriptorOffset(code_info)
+              << ", register_mask=0x" << GetRegisterMask(code_info)
+              << std::dec
+              << ", stack_mask=0b";
+  MemoryRegion stack_mask = GetStackMask(code_info);
+  for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
+    indented_os << stack_mask.LoadBit(e - i - 1);
+  }
+  indented_os << ")\n";
+  if (HasDexRegisterMap(code_info)) {
+    DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(*this, number_of_dex_registers);
+    dex_register_map.Dump(os, code_info, number_of_dex_registers);
+  }
+}
+
 void InlineInfo::Dump(std::ostream& os,
                       const CodeInfo& code_info,
                       uint16_t number_of_dex_registers[]) const {
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index eefdaa7..f17fe1b 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -696,6 +696,12 @@
                                     size_t native_pc_max,
                                     size_t register_mask_max);
 
+  void Dump(std::ostream& os,
+            const CodeInfo& code_info,
+            uint32_t code_offset,
+            uint16_t number_of_dex_registers,
+            const std::string& header_suffix = "") const;
+
   // 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;
@@ -1048,16 +1054,15 @@
     return StackMap();
   }
 
-  // Dump this CodeInfo object on `os`.  If `dump_stack_maps` is true,
-  // also dump the stack maps and the associated Dex register maps.
-  void Dump(std::ostream& os, uint16_t number_of_dex_registers, bool dump_stack_maps) const;
-
-  // Dump stack map number `stack_map_num` as well as associated data on `os`,
-  // such as Dex register locations.
-  void DumpStackMap(std::ostream& os, size_t stack_map_num, uint16_t number_of_dex_registers) const;
-  // Dump the header of stack map number `stack_map_num` on `os`, without
-  // associated data.
-  void DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const;
+  // Dump this CodeInfo object on `os`.  `code_offset` is the (absolute)
+  // native PC of the compiled method and `number_of_dex_registers` the
+  // number of Dex virtual registers used in this method.  If
+  // `dump_stack_maps` is true, also dump the stack maps and the
+  // associated Dex register maps.
+  void Dump(std::ostream& os,
+            uint32_t code_offset,
+            uint16_t number_of_dex_registers,
+            bool dump_stack_maps) const;
 
  private:
   // TODO: Instead of plain types such as "uint32_t", introduce