Pack stack map entries on bit level to save space.

Use only the minimum number of bits required to store stack map data.
For example, if native_pc needs 5 bits and dex_pc needs 3 bits, they
will share the first byte of the stack map entry.

The header is changed to store bit offsets of the fields rather than
byte sizes. Offsets also make it easier to access later fields without
calculating sum of all previous sizes.

All of the header fields are byte sized or encoded as ULEB128 instead
of the previous fixed size encoding. This shrinks it by about half.

It saves 3.6 MB from non-debuggable boot.oat (AOSP).
It saves 3.1 MB from debuggable boot.oat (AOSP).

It saves 2.8 MB (of 99.4 MB) from /system/framework/arm/ (GOOG).
It saves 1.0 MB (of 27.8 MB) from /system/framework/oat/arm/ (GOOG).

Field loads from stackmaps seem to get around 10% faster.
(based on the time it takes to load all stackmap entries from boot.oat)

Bug: 27640410
Change-Id: I8bf0996b4eb24300c1b0dfc6e9d99fe85d04a1b7
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 3093436..b51baf1 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -56,66 +56,29 @@
     uint16_t dex_register_number,
     uint16_t number_of_dex_registers,
     const CodeInfo& code_info,
-    const StackMapEncoding& enc) const {
+    const CodeInfoEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
       code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
-      code_info.GetNumberOfLocationCatalogEntries());
+      code_info.GetNumberOfLocationCatalogEntries(enc));
   return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
 }
 
 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
                                                            uint16_t number_of_dex_registers,
                                                            const CodeInfo& code_info,
-                                                           const StackMapEncoding& enc) const {
+                                                           const CodeInfoEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
       code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
-      code_info.GetNumberOfLocationCatalogEntries());
+      code_info.GetNumberOfLocationCatalogEntries(enc));
   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
 }
 
-uint32_t StackMap::LoadAt(size_t number_of_bytes, size_t offset, bool check_max) const {
-  if (number_of_bytes == 0u) {
-    DCHECK(!check_max);
-    return 0;
-  } else if (number_of_bytes == 1u) {
-    uint8_t value = region_.LoadUnaligned<uint8_t>(offset);
-    return (check_max && value == 0xFF) ? -1 : value;
-  } else if (number_of_bytes == 2u) {
-    uint16_t value = region_.LoadUnaligned<uint16_t>(offset);
-    return (check_max && value == 0xFFFF) ? -1 : value;
-  } else if (number_of_bytes == 3u) {
-    uint16_t low = region_.LoadUnaligned<uint16_t>(offset);
-    uint16_t high = region_.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
-    uint32_t value = (high << 16) + low;
-    return (check_max && value == 0xFFFFFF) ? -1 : value;
-  } else {
-    DCHECK_EQ(number_of_bytes, 4u);
-    return region_.LoadUnaligned<uint32_t>(offset);
-  }
-}
-
-void StackMap::StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const {
-  if (number_of_bytes == 0u) {
-    DCHECK_EQ(value, 0u);
-  } else if (number_of_bytes == 1u) {
-    region_.StoreUnaligned<uint8_t>(offset, value);
-  } else if (number_of_bytes == 2u) {
-    region_.StoreUnaligned<uint16_t>(offset, value);
-  } else if (number_of_bytes == 3u) {
-    region_.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
-    region_.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
-  } else {
-    region_.StoreUnaligned<uint32_t>(offset, value);
-    DCHECK_EQ(number_of_bytes, 4u);
-  }
-}
-
 static void DumpRegisterMapping(std::ostream& os,
                                 size_t dex_register_num,
                                 DexRegisterLocation location,
@@ -126,25 +89,30 @@
      << " (" << location.GetValue() << ")" << suffix << '\n';
 }
 
+void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const {
+  vios->Stream()
+      << "StackMapEncoding"
+      << " (native_pc_bit_offset=" << static_cast<uint32_t>(kNativePcBitOffset)
+      << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
+      << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
+      << ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_)
+      << ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_bit_offset_)
+      << ", stack_mask_bit_offset=" << static_cast<uint32_t>(stack_mask_bit_offset_)
+      << ")\n";
+}
+
 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     bool dump_stack_maps) const {
-  StackMapEncoding encoding = ExtractEncoding();
-  uint32_t code_info_size = GetOverallSize();
-  size_t number_of_stack_maps = GetNumberOfStackMaps();
+  CodeInfoEncoding encoding = ExtractEncoding();
+  size_t number_of_stack_maps = GetNumberOfStackMaps(encoding);
   vios->Stream()
-      << "Optimized CodeInfo (size=" << code_info_size
-      << ", number_of_dex_registers=" << number_of_dex_registers
+      << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers
       << ", number_of_stack_maps=" << number_of_stack_maps
-      << ", has_inline_info=" << encoding.HasInlineInfo()
-      << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
-      << ", number_of_bytes_for_dex_register_map=" << encoding.NumberOfBytesForDexRegisterMap()
-      << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
-      << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
-      << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
       << ")\n";
   ScopedIndentation indent1(vios);
+  encoding.stack_map_encoding.Dump(vios);
   // Display the Dex register location catalog.
   GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
   // Display stack maps along with (live) Dex register maps.
@@ -165,8 +133,8 @@
 
 void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
                                       const CodeInfo& code_info) {
-  StackMapEncoding encoding = code_info.ExtractEncoding();
-  size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
+  CodeInfoEncoding encoding = code_info.ExtractEncoding();
+  size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
   size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
   vios->Stream()
       << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
@@ -181,8 +149,8 @@
 void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
                           const CodeInfo& code_info,
                           uint16_t number_of_dex_registers) const {
-  StackMapEncoding encoding = code_info.ExtractEncoding();
-  size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
+  CodeInfoEncoding encoding = code_info.ExtractEncoding();
+  size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
   // TODO: Display the bit mask of live Dex registers.
   for (size_t j = 0; j < number_of_dex_registers; ++j) {
     if (IsDexRegisterLive(j)) {
@@ -202,32 +170,32 @@
 
 void StackMap::Dump(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
-                    const StackMapEncoding& encoding,
+                    const CodeInfoEncoding& encoding,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     const std::string& header_suffix) const {
+  StackMapEncoding stack_map_encoding = encoding.stack_map_encoding;
   vios->Stream()
       << "StackMap" << header_suffix
       << std::hex
-      << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
-      << " (dex_pc=0x" << GetDexPc(encoding)
-      << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
-      << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
-      << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
-      << ", register_mask=0x" << GetRegisterMask(encoding)
+      << " [native_pc=0x" << code_offset + GetNativePcOffset(stack_map_encoding) << "]"
+      << " (dex_pc=0x" << GetDexPc(stack_map_encoding)
+      << ", native_pc_offset=0x" << GetNativePcOffset(stack_map_encoding)
+      << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding)
+      << ", inline_info_offset=0x" << GetInlineDescriptorOffset(stack_map_encoding)
+      << ", register_mask=0x" << GetRegisterMask(stack_map_encoding)
       << std::dec
       << ", stack_mask=0b";
-  MemoryRegion stack_mask = GetStackMask(encoding);
-  for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    vios->Stream() << stack_mask.LoadBit(e - i - 1);
+  for (size_t i = 0, e = GetNumberOfStackMaskBits(stack_map_encoding); i < e; ++i) {
+    vios->Stream() << GetStackMaskBit(stack_map_encoding, e - i - 1);
   }
   vios->Stream() << ")\n";
-  if (HasDexRegisterMap(encoding)) {
+  if (HasDexRegisterMap(stack_map_encoding)) {
     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
         *this, encoding, number_of_dex_registers);
     dex_register_map.Dump(vios, code_info, number_of_dex_registers);
   }
-  if (HasInlineInfo(encoding)) {
+  if (HasInlineInfo(stack_map_encoding)) {
     InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
     // We do not know the length of the dex register maps of inlined frames
     // at this level, so we just pass null to `InlineInfo::Dump` to tell
@@ -251,7 +219,7 @@
         << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
         << ")\n";
     if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
-      StackMapEncoding encoding = code_info.ExtractEncoding();
+      CodeInfoEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
       ScopedIndentation indent1(vios);