Deduplicate stack masks

The stack masks repeat often enough so that it is worth deduplicating
them.

Oat size for a large app:
98143600 -> 96722288 (-1.44%)

Bug: 34621054

Test: test-art-host
Change-Id: If73d51e46066357049d5be2e406ae9a32b7ff1f4
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 679218d..83ba457 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -695,34 +695,34 @@
                       size_t dex_register_map_size,
                       size_t inline_info_size,
                       size_t register_mask_max,
-                      size_t stack_mask_bit_size) {
-    size_t bit_offset = 0;
-    DCHECK_EQ(kNativePcBitOffset, bit_offset);
-    bit_offset += MinimumBitsToStore(native_pc_max);
+                      size_t number_of_stack_masks) {
+    total_bit_size_ = 0;
+    DCHECK_EQ(kNativePcBitOffset, total_bit_size_);
+    total_bit_size_ += MinimumBitsToStore(native_pc_max);
 
-    dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
-    bit_offset += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
+    dex_pc_bit_offset_ = total_bit_size_;
+    total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
 
     // We also need +1 for kNoDexRegisterMap, but since the size is strictly
     // greater than any offset we might try to encode, we already implicitly have it.
-    dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
-    bit_offset += MinimumBitsToStore(dex_register_map_size);
+    dex_register_map_bit_offset_ = total_bit_size_;
+    total_bit_size_ += MinimumBitsToStore(dex_register_map_size);
 
     // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly
     // greater than the offset we might try to encode, we already implicitly have it.
     // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits).
-    inline_info_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
+    inline_info_bit_offset_ = total_bit_size_;
     if (inline_info_size != 0) {
-      bit_offset += MinimumBitsToStore(dex_register_map_size + inline_info_size);
+      total_bit_size_ += MinimumBitsToStore(dex_register_map_size + inline_info_size);
     }
 
-    register_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
-    bit_offset += MinimumBitsToStore(register_mask_max);
+    register_mask_bit_offset_ = total_bit_size_;
+    total_bit_size_ += MinimumBitsToStore(register_mask_max);
 
-    stack_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
-    bit_offset += stack_mask_bit_size;
+    stack_mask_index_bit_offset_ = total_bit_size_;
+    total_bit_size_ += MinimumBitsToStore(number_of_stack_masks);
 
-    return bit_offset;
+    return total_bit_size_;
   }
 
   ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const {
@@ -738,15 +738,13 @@
     return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */);
   }
   ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const {
-    return FieldEncoding(register_mask_bit_offset_, stack_mask_bit_offset_);
+    return FieldEncoding(register_mask_bit_offset_, stack_mask_index_bit_offset_);
   }
-  ALWAYS_INLINE size_t GetStackMaskBitOffset() const {
-    // The end offset is not encoded. It is implicitly the end of stack map entry.
-    return stack_mask_bit_offset_;
+  ALWAYS_INLINE FieldEncoding GetStackMaskIndexEncoding() const {
+    return FieldEncoding(stack_mask_index_bit_offset_, total_bit_size_);
   }
-  ALWAYS_INLINE size_t GetNumberOfStackMaskBits(size_t stack_map_bits) const {
-    // Note that the stack mask bits are last.
-    return stack_map_bits - GetStackMaskBitOffset();
+  ALWAYS_INLINE size_t BitSize() const {
+    return total_bit_size_;
   }
 
   void Dump(VariableIndentationOutputStream* vios) const;
@@ -757,7 +755,8 @@
   uint8_t dex_register_map_bit_offset_;
   uint8_t inline_info_bit_offset_;
   uint8_t register_mask_bit_offset_;
-  uint8_t stack_mask_bit_offset_;
+  uint8_t stack_mask_index_bit_offset_;
+  uint8_t total_bit_size_;
 };
 
 /**
@@ -771,7 +770,7 @@
  * The information is of the form:
  *
  *   [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask,
- *   stack_mask].
+ *   stack_mask_index].
  */
 class StackMap {
  public:
@@ -824,12 +823,12 @@
     encoding.GetRegisterMaskEncoding().Store(region_, mask);
   }
 
-  ALWAYS_INLINE bool GetStackMaskBit(const StackMapEncoding& encoding, size_t index) const {
-    return region_.LoadBit(encoding.GetStackMaskBitOffset() + index);
+  ALWAYS_INLINE uint32_t GetStackMaskIndex(const StackMapEncoding& encoding) const {
+    return encoding.GetStackMaskIndexEncoding().Load(region_);
   }
 
-  ALWAYS_INLINE void SetStackMaskBit(const StackMapEncoding& encoding, size_t index, bool value) {
-    region_.StoreBit(encoding.GetStackMaskBitOffset() + index, value);
+  ALWAYS_INLINE void SetStackMaskIndex(const StackMapEncoding& encoding, uint32_t mask) {
+    encoding.GetStackMaskIndexEncoding().Store(region_, mask);
   }
 
   ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
@@ -1031,7 +1030,8 @@
 struct CodeInfoEncoding {
   uint32_t non_header_size;
   uint32_t number_of_stack_maps;
-  uint32_t stack_map_size_in_bits;
+  uint32_t number_of_stack_masks;
+  uint32_t stack_mask_size_in_bits;
   uint32_t number_of_location_catalog_entries;
   StackMapEncoding stack_map_encoding;
   InlineInfoEncoding inline_info_encoding;
@@ -1043,7 +1043,8 @@
     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
     non_header_size = DecodeUnsignedLeb128(&ptr);
     number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
-    stack_map_size_in_bits = DecodeUnsignedLeb128(&ptr);
+    number_of_stack_masks = DecodeUnsignedLeb128(&ptr);
+    stack_mask_size_in_bits = DecodeUnsignedLeb128(&ptr);
     number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
     static_assert(alignof(StackMapEncoding) == 1,
                   "StackMapEncoding should not require alignment");
@@ -1064,7 +1065,8 @@
   void Compress(Vector* dest) const {
     EncodeUnsignedLeb128(dest, non_header_size);
     EncodeUnsignedLeb128(dest, number_of_stack_maps);
-    EncodeUnsignedLeb128(dest, stack_map_size_in_bits);
+    EncodeUnsignedLeb128(dest, number_of_stack_masks);
+    EncodeUnsignedLeb128(dest, stack_mask_size_in_bits);
     EncodeUnsignedLeb128(dest, number_of_location_catalog_entries);
     const uint8_t* stack_map_ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
     dest->insert(dest->end(), stack_map_ptr, stack_map_ptr + sizeof(StackMapEncoding));
@@ -1098,7 +1100,7 @@
   }
 
   CodeInfoEncoding ExtractEncoding() const {
-    CodeInfoEncoding encoding(region_.start());
+    CodeInfoEncoding encoding(region_.begin());
     AssertValidStackMap(encoding);
     return encoding;
   }
@@ -1114,14 +1116,27 @@
   }
 
   ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const CodeInfoEncoding& encoding) const {
-    return encoding.stack_map_encoding.GetNumberOfStackMaskBits(encoding.stack_map_size_in_bits);
+    return encoding.stack_mask_size_in_bits;
   }
 
   ALWAYS_INLINE StackMap GetStackMapAt(size_t i, const CodeInfoEncoding& encoding) const {
-    const size_t map_size = encoding.stack_map_size_in_bits;
+    const size_t map_size = encoding.stack_map_encoding.BitSize();
     return StackMap(BitMemoryRegion(GetStackMaps(encoding), i * map_size, map_size));
   }
 
+  BitMemoryRegion GetStackMask(const CodeInfoEncoding& encoding, size_t stack_mask_index) const {
+    // All stack mask data is stored at the very end.
+    const size_t entry_size = GetNumberOfStackMaskBits(encoding);
+    return BitMemoryRegion(region_,
+                           region_.size_in_bits() - entry_size * (stack_mask_index + 1),
+                           entry_size);
+  }
+
+  BitMemoryRegion GetStackMaskOf(const CodeInfoEncoding& encoding,
+                                 const StackMap& stack_map) const {
+    return GetStackMask(encoding, stack_map.GetStackMaskIndex(encoding.stack_map_encoding));
+  }
+
   uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const {
     return encoding.number_of_location_catalog_entries;
   }
@@ -1135,10 +1150,14 @@
     return encoding.number_of_stack_maps;
   }
 
+  // Get the size of all the stack maps of this CodeInfo object, in bits. Not byte aligned.
+  ALWAYS_INLINE size_t GetStackMapsSizeInBits(const CodeInfoEncoding& encoding) const {
+    return encoding.stack_map_encoding.BitSize() * GetNumberOfStackMaps(encoding);
+  }
+
   // Get the size of all the stack maps of this CodeInfo object, in bytes.
   size_t GetStackMapsSize(const CodeInfoEncoding& encoding) const {
-    return RoundUp(encoding.stack_map_size_in_bits * GetNumberOfStackMaps(encoding), kBitsPerByte) /
-        kBitsPerByte;
+    return RoundUp(GetStackMapsSizeInBits(encoding), kBitsPerByte) / kBitsPerByte;
   }
 
   uint32_t GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding& encoding) const {
@@ -1288,7 +1307,7 @@
                  << encoding.non_header_size << "\n"
                  << encoding.number_of_location_catalog_entries << "\n"
                  << encoding.number_of_stack_maps << "\n"
-                 << encoding.stack_map_size_in_bits;
+                 << encoding.stack_map_encoding.BitSize();
     }
   }