Deduplicate register masks

Data is commonly shared between different stack maps. The register
masks are stored after the stack masks.

Oat size for a large app:
96722288 -> 94485872 (-2.31%)

Average oat size reduction according to golem -3.193%.

Bug: 34621054

Test: test-art-host

Change-Id: I5eacf668992e866d11ddba0c01675038a16cdfb4
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 83ba457..062404d 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -694,7 +694,7 @@
                       size_t dex_pc_max,
                       size_t dex_register_map_size,
                       size_t inline_info_size,
-                      size_t register_mask_max,
+                      size_t number_of_register_masks,
                       size_t number_of_stack_masks) {
     total_bit_size_ = 0;
     DCHECK_EQ(kNativePcBitOffset, total_bit_size_);
@@ -716,8 +716,8 @@
       total_bit_size_ += MinimumBitsToStore(dex_register_map_size + inline_info_size);
     }
 
-    register_mask_bit_offset_ = total_bit_size_;
-    total_bit_size_ += MinimumBitsToStore(register_mask_max);
+    register_mask_index_bit_offset_ = total_bit_size_;
+    total_bit_size_ += MinimumBitsToStore(number_of_register_masks);
 
     stack_mask_index_bit_offset_ = total_bit_size_;
     total_bit_size_ += MinimumBitsToStore(number_of_stack_masks);
@@ -735,10 +735,12 @@
     return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */);
   }
   ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const {
-    return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */);
+    return FieldEncoding(inline_info_bit_offset_,
+                         register_mask_index_bit_offset_,
+                         -1 /* min_value */);
   }
-  ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const {
-    return FieldEncoding(register_mask_bit_offset_, stack_mask_index_bit_offset_);
+  ALWAYS_INLINE FieldEncoding GetRegisterMaskIndexEncoding() const {
+    return FieldEncoding(register_mask_index_bit_offset_, stack_mask_index_bit_offset_);
   }
   ALWAYS_INLINE FieldEncoding GetStackMaskIndexEncoding() const {
     return FieldEncoding(stack_mask_index_bit_offset_, total_bit_size_);
@@ -754,7 +756,7 @@
   uint8_t dex_pc_bit_offset_;
   uint8_t dex_register_map_bit_offset_;
   uint8_t inline_info_bit_offset_;
-  uint8_t register_mask_bit_offset_;
+  uint8_t register_mask_index_bit_offset_;
   uint8_t stack_mask_index_bit_offset_;
   uint8_t total_bit_size_;
 };
@@ -769,7 +771,7 @@
  *
  * The information is of the form:
  *
- *   [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask,
+ *   [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask_index,
  *   stack_mask_index].
  */
 class StackMap {
@@ -815,12 +817,12 @@
     encoding.GetInlineInfoEncoding().Store(region_, offset);
   }
 
-  ALWAYS_INLINE uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
-    return encoding.GetRegisterMaskEncoding().Load(region_);
+  ALWAYS_INLINE uint32_t GetRegisterMaskIndex(const StackMapEncoding& encoding) const {
+    return encoding.GetRegisterMaskIndexEncoding().Load(region_);
   }
 
-  ALWAYS_INLINE void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
-    encoding.GetRegisterMaskEncoding().Store(region_, mask);
+  ALWAYS_INLINE void SetRegisterMaskIndex(const StackMapEncoding& encoding, uint32_t mask) {
+    encoding.GetRegisterMaskIndexEncoding().Store(region_, mask);
   }
 
   ALWAYS_INLINE uint32_t GetStackMaskIndex(const StackMapEncoding& encoding) const {
@@ -1031,7 +1033,9 @@
   uint32_t non_header_size;
   uint32_t number_of_stack_maps;
   uint32_t number_of_stack_masks;
+  uint32_t number_of_register_masks;
   uint32_t stack_mask_size_in_bits;
+  uint32_t register_mask_size_in_bits;
   uint32_t number_of_location_catalog_entries;
   StackMapEncoding stack_map_encoding;
   InlineInfoEncoding inline_info_encoding;
@@ -1044,7 +1048,9 @@
     non_header_size = DecodeUnsignedLeb128(&ptr);
     number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
     number_of_stack_masks = DecodeUnsignedLeb128(&ptr);
+    number_of_register_masks = DecodeUnsignedLeb128(&ptr);
     stack_mask_size_in_bits = DecodeUnsignedLeb128(&ptr);
+    register_mask_size_in_bits = DecodeUnsignedLeb128(&ptr);
     number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
     static_assert(alignof(StackMapEncoding) == 1,
                   "StackMapEncoding should not require alignment");
@@ -1066,7 +1072,9 @@
     EncodeUnsignedLeb128(dest, non_header_size);
     EncodeUnsignedLeb128(dest, number_of_stack_maps);
     EncodeUnsignedLeb128(dest, number_of_stack_masks);
+    EncodeUnsignedLeb128(dest, number_of_register_masks);
     EncodeUnsignedLeb128(dest, stack_mask_size_in_bits);
+    EncodeUnsignedLeb128(dest, register_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));
@@ -1125,10 +1133,13 @@
   }
 
   BitMemoryRegion GetStackMask(const CodeInfoEncoding& encoding, size_t stack_mask_index) const {
-    // All stack mask data is stored at the very end.
+    // All stack mask data is stored before register map data (which is at the very end).
     const size_t entry_size = GetNumberOfStackMaskBits(encoding);
+    const size_t register_mask_bits =
+        encoding.register_mask_size_in_bits * encoding.number_of_register_masks;
     return BitMemoryRegion(region_,
-                           region_.size_in_bits() - entry_size * (stack_mask_index + 1),
+                           region_.size_in_bits() - register_mask_bits -
+                               entry_size * (stack_mask_index + 1),
                            entry_size);
   }
 
@@ -1137,6 +1148,18 @@
     return GetStackMask(encoding, stack_map.GetStackMaskIndex(encoding.stack_map_encoding));
   }
 
+  BitMemoryRegion GetRegisterMask(const CodeInfoEncoding& encoding, size_t index) const {
+    const size_t entry_size = encoding.register_mask_size_in_bits;
+    return BitMemoryRegion(region_,
+                           region_.size_in_bits() - entry_size * (index + 1),
+                           entry_size);
+  }
+
+  uint32_t GetRegisterMaskOf(const CodeInfoEncoding& encoding, const StackMap& stack_map) const {
+    size_t index = stack_map.GetRegisterMaskIndex(encoding.stack_map_encoding);
+    return GetRegisterMask(encoding, index).LoadBits(0u, encoding.register_mask_size_in_bits);
+  }
+
   uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const {
     return encoding.number_of_location_catalog_entries;
   }