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_,