Add more code info size dumping to oatdump

Helps break down where oat bytes are being used, example output on
a large app:

OAT FILE STATS:
Dumping cumulative use of 95784720 accounted bytes
Code                            = 68894196 (72% of total)
QuickMethodHeader               =  3071080 ( 3% of total)
CodeInfoEncoding                =  1226080 ( 1% of total)
CodeInfoLocationCatalog         =  1005716 ( 1% of total)
CodeInfoDexRegisterMap          =  5813389 ( 6% of total)
CodeInfoInlineInfo              =  2391251 ( 2% of total)
CodeInfoStackMap                = 13383008 (14% of total)
  StackMapNativePc              =  1607888 (12% of stack map)
  StackMapDexPcEncoding         =  1116724 ( 8% of stack map)
  StackMapDexRegisterMap        =  1277680 (10% of stack map)
  StackMapInlineInfo            =  1082720 ( 8% of stack map)
  StackMapRegisterMaskEncoding  =  5104960 (38% of stack map)
  StackMapMask                  =  3193034 (24% of stack map)
  StackMapOther                 =        0 ( 0% of stack map)

Test: test-art-host, oatdump

Bug: 34621054

Change-Id: I5daf0f1308d126b6a30928f523c6051585f1491f
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 3cf900e..3f52434 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -529,6 +529,12 @@
       }
     }
 
+    {
+      os << "OAT FILE STATS:\n";
+      VariableIndentationOutputStream vios(&os);
+      stats_.Dump(vios);
+    }
+
     os << std::flush;
     return success;
   }
@@ -574,6 +580,116 @@
     return nullptr;
   }
 
+  struct Stats {
+    enum ByteKind {
+      kByteKindCode,
+      kByteKindQuickMethodHeader,
+      kByteKindCodeInfoLocationCatalog,
+      kByteKindCodeInfoDexRegisterMap,
+      kByteKindCodeInfoInlineInfo,
+      kByteKindCodeInfoEncoding,
+      kByteKindCodeInfoOther,
+      kByteKindStackMapNativePc,
+      kByteKindStackMapDexPc,
+      kByteKindStackMapDexRegisterMap,
+      kByteKindStackMapInlineInfo,
+      kByteKindStackMapRegisterMask,
+      kByteKindStackMapMask,
+      kByteKindStackMapOther,
+      kByteKindCount,
+      kByteKindStackMapFirst = kByteKindCodeInfoOther,
+      kByteKindStackMapLast = kByteKindStackMapOther,
+    };
+    int64_t bits[kByteKindCount] = {};
+    // Since code has deduplication, seen tracks already seen pointers to avoid double counting
+    // deduplicated code and tables.
+    std::unordered_set<const void*> seen;
+
+    // Returns true if it was newly added.
+    bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) {
+      if (seen.insert(address).second == true) {
+        // True means the address was not already in the set.
+        AddBits(kind, count);
+        return true;
+      }
+      return false;
+    }
+
+    void AddBits(ByteKind kind, int64_t count) {
+      bits[kind] += count;
+    }
+
+    void Dump(VariableIndentationOutputStream& os) {
+      const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u);
+      os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n";
+      if (sum > 0) {
+        const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst,
+                                                       bits + kByteKindStackMapLast + 1,
+                                                       0u);
+        Dump(os, "Code                           ", bits[kByteKindCode], sum);
+        Dump(os, "QuickMethodHeader              ", bits[kByteKindQuickMethodHeader], sum);
+        Dump(os, "CodeInfoEncoding               ", bits[kByteKindCodeInfoEncoding], sum);
+        Dump(os, "CodeInfoLocationCatalog        ", bits[kByteKindCodeInfoLocationCatalog], sum);
+        Dump(os, "CodeInfoDexRegisterMap         ", bits[kByteKindCodeInfoDexRegisterMap], sum);
+        Dump(os, "CodeInfoInlineInfo             ", bits[kByteKindCodeInfoInlineInfo], sum);
+        Dump(os, "CodeInfoStackMap               ", stack_map_bits, sum);
+        {
+          ScopedIndentation indent1(&os);
+          Dump(os,
+               "StackMapNativePc             ",
+               bits[kByteKindStackMapNativePc],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapDexPcEncoding        ",
+               bits[kByteKindStackMapDexPc],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapDexRegisterMap       ",
+               bits[kByteKindStackMapDexRegisterMap],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapInlineInfo           ",
+               bits[kByteKindStackMapInlineInfo],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapRegisterMaskEncoding ",
+               bits[kByteKindStackMapRegisterMask],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapMask                 ",
+               bits[kByteKindStackMapMask],
+               stack_map_bits,
+               "stack map");
+          Dump(os,
+               "StackMapOther                ",
+               bits[kByteKindStackMapOther],
+               stack_map_bits,
+               "stack map");
+        }
+      }
+      os.Stream() << "\n" << std::flush;
+    }
+
+   private:
+    void Dump(VariableIndentationOutputStream& os,
+              const char* name,
+              int64_t size,
+              int64_t total,
+              const char* sum_of = "total") {
+      const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100;
+      os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n",
+                                  name,
+                                  size / kBitsPerByte,
+                                  percent,
+                                  sum_of);
+    }
+  };
+
  private:
   void AddAllOffsets() {
     // We don't know the length of the code for each method, but we need to know where to stop
@@ -1046,7 +1162,9 @@
       vios->Stream() << "OatQuickMethodHeader ";
       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
-
+      stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader,
+                             sizeof(*method_header) * kBitsPerByte,
+                             method_header);
       if (options_.absolute_addresses_) {
         vios->Stream() << StringPrintf("%p ", method_header);
       }
@@ -1118,6 +1236,7 @@
         const void* code = oat_method.GetQuickCode();
         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
         uint64_t aligned_code_end = aligned_code_begin + code_size;
+        stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code);
 
         if (options_.absolute_addresses_) {
           vios->Stream() << StringPrintf("%p ", code);
@@ -1431,6 +1550,60 @@
     } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
       // The optimizing compiler outputs its CodeInfo data in the vmap table.
       StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
+      {
+        CodeInfoEncoding encoding(helper.GetEncoding());
+        StackMapEncoding stack_map_encoding(encoding.stack_map_encoding);
+        // helper.GetCodeInfo().GetStackMapAt(0, encoding).;
+        const size_t num_stack_maps = encoding.number_of_stack_maps;
+        std::vector<uint8_t> size_vector;
+        encoding.Compress(&size_vector);
+        if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding,
+                                   size_vector.size() * kBitsPerByte,
+                                   oat_method.GetVmapTable())) {
+          stats_.AddBits(
+              Stats::kByteKindStackMapNativePc,
+              stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps);
+          stats_.AddBits(
+              Stats::kByteKindStackMapDexPc,
+              stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps);
+          stats_.AddBits(
+              Stats::kByteKindStackMapDexRegisterMap,
+              stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps);
+          stats_.AddBits(
+              Stats::kByteKindStackMapInlineInfo,
+              stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps);
+          stats_.AddBits(
+              Stats::kByteKindStackMapRegisterMask,
+              stack_map_encoding.GetRegisterMaskEncoding().BitSize() * num_stack_maps);
+          const size_t stack_mask_bits = encoding.stack_map_size_in_bytes * kBitsPerByte -
+              stack_map_encoding.GetStackMaskBitOffset();
+          stats_.AddBits(
+              Stats::kByteKindStackMapMask,
+              stack_mask_bits * num_stack_maps);
+          const size_t stack_map_bits =
+              stack_map_encoding.GetStackMaskBitOffset() + stack_mask_bits;
+          stats_.AddBits(
+              Stats::kByteKindStackMapOther,
+              (encoding.stack_map_size_in_bytes * kBitsPerByte - stack_map_bits) * num_stack_maps);
+          const size_t stack_map_bytes = helper.GetCodeInfo().GetStackMapsSize(encoding);
+          const size_t location_catalog_bytes =
+              helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding);
+          stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog,
+                         kBitsPerByte * location_catalog_bytes);
+          const size_t dex_register_bytes =
+              helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_);
+          stats_.AddBits(
+              Stats::kByteKindCodeInfoDexRegisterMap,
+              kBitsPerByte * dex_register_bytes);
+          const size_t inline_info_bytes =
+              encoding.non_header_size -
+              stack_map_bytes -
+              location_catalog_bytes -
+              dex_register_bytes;
+          stats_.AddBits(Stats::kByteKindCodeInfoInlineInfo,
+                         inline_info_bytes * kBitsPerByte);
+        }
+      }
       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
       size_t offset = 0;
       while (offset < code_size) {
@@ -1468,6 +1641,7 @@
   const InstructionSet instruction_set_;
   std::set<uintptr_t> offsets_;
   Disassembler* disassembler_;
+  Stats stats_;
 };
 
 class ImageDumper {
@@ -2140,7 +2314,6 @@
 
     size_t managed_code_bytes;
     size_t managed_code_bytes_ignoring_deduplication;
-    size_t managed_to_native_code_bytes;
     size_t native_to_managed_code_bytes;
     size_t class_initializer_code_bytes;
     size_t large_initializer_code_bytes;
@@ -2169,7 +2342,6 @@
           alignment_bytes(0),
           managed_code_bytes(0),
           managed_code_bytes_ignoring_deduplication(0),
-          managed_to_native_code_bytes(0),
           native_to_managed_code_bytes(0),
           class_initializer_code_bytes(0),
           large_initializer_code_bytes(0),
@@ -2367,7 +2539,6 @@
 
       os << StringPrintf("oat_file_bytes               = %8zd\n"
                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
-                         "managed_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
@@ -2375,8 +2546,6 @@
                          oat_file_bytes,
                          managed_code_bytes,
                          PercentOfOatBytes(managed_code_bytes),
-                         managed_to_native_code_bytes,
-                         PercentOfOatBytes(managed_to_native_code_bytes),
                          native_to_managed_code_bytes,
                          PercentOfOatBytes(native_to_managed_code_bytes),
                          class_initializer_code_bytes,
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index e77d03b..ba57d18 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -102,6 +102,7 @@
         // Code and dex code do not show up if list only.
         expected_prefixes.push_back("DEX CODE:");
         expected_prefixes.push_back("CODE:");
+        expected_prefixes.push_back("CodeInfoEncoding");
       }
       if (mode == kModeArt) {
         exec_argv.push_back("--image=" + core_art_location_);
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 3c92b86..690b069 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -198,6 +198,7 @@
       << "StackMap" << header_suffix
       << std::hex
       << " [native_pc=0x" << code_offset + pc_offset << "]"
+      << " [entry_size=0x" << encoding.stack_map_size_in_bytes << "]"
       << " (dex_pc=0x" << GetDexPc(stack_map_encoding)
       << ", native_pc_offset=0x" << pc_offset
       << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding)
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 28c4b88..cd9a3f0 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -1182,6 +1182,17 @@
     }
   }
 
+  size_t GetDexRegisterMapsSize(const CodeInfoEncoding& encoding,
+                                uint32_t number_of_dex_registers) const {
+    size_t total = 0;
+    for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
+      StackMap stack_map = GetStackMapAt(i, encoding);
+      DexRegisterMap map(GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers));
+      total += map.Size();
+    }
+    return total;
+  }
+
   // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
   DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
                                           InlineInfo inline_info,