Deduplicate register maps for both inline and normal stack maps

Before it only deduplicated the normal stack map dex register maps.
Code size for a large app: 93341616 -> 92678040 (-0.7%)

Added test.

Bug: 34621054

Test: test-art-host

Change-Id: I4fab4e40915bfa12cb978edbb3cbc19e2cf00954
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index bd0aa6d..0416951 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -410,6 +410,100 @@
   }
 }
 
+TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  StackMapStream stream(&arena, kRuntimeISA);
+  ArtMethod art_method;
+
+  ArenaBitVector sp_mask1(&arena, 0, true);
+  sp_mask1.SetBit(2);
+  sp_mask1.SetBit(4);
+  const size_t number_of_dex_registers = 2;
+  const size_t number_of_dex_registers_in_inline_info = 2;
+  stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 1);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
+  stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
+  stream.EndInlineInfoEntry();
+  stream.EndStackMapEntry();
+
+  size_t size = stream.PrepareForFillIn();
+  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  MemoryRegion region(memory, size);
+  stream.FillIn(region);
+
+  CodeInfo code_info(region);
+  CodeInfoEncoding encoding = code_info.ExtractEncoding();
+  ASSERT_EQ(1u, code_info.GetNumberOfStackMaps(encoding));
+
+  uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
+  ASSERT_EQ(2u, number_of_catalog_entries);
+  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding);
+  // The Dex register location catalog contains:
+  // - one 1-byte short Dex register locations, and
+  // - one 5-byte large Dex register location.
+  const size_t expected_location_catalog_size = 1u + 5u;
+  ASSERT_EQ(expected_location_catalog_size, location_catalog.Size());
+
+  // First stack map.
+  {
+    StackMap stack_map = code_info.GetStackMapAt(0, encoding);
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding)));
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding)));
+    ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding));
+    ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA));
+    ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map));
+
+    ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask1));
+
+    ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding));
+    DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers));
+    ASSERT_TRUE(map.IsDexRegisterLive(0));
+    ASSERT_TRUE(map.IsDexRegisterLive(1));
+    ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters(number_of_dex_registers));
+    // The Dex register map contains:
+    // - one 1-byte live bit mask, and
+    // - one 1-byte set of location catalog entry indices composed of two 2-bit values.
+    size_t expected_map_size = 1u + 1u;
+    ASSERT_EQ(expected_map_size, map.Size());
+
+    ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kConstant,
+              map.GetLocationKind(1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kInStack,
+              map.GetLocationInternalKind(0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kConstantLargeValue,
+              map.GetLocationInternalKind(1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(0, map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(-2, map.GetConstant(1, number_of_dex_registers, code_info, encoding));
+
+    const size_t index0 =
+        map.GetLocationCatalogEntryIndex(0, number_of_dex_registers, number_of_catalog_entries);
+    const size_t index1 =
+        map.GetLocationCatalogEntryIndex(1, number_of_dex_registers, number_of_catalog_entries);
+    ASSERT_EQ(0u, index0);
+    ASSERT_EQ(1u, index1);
+    DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0);
+    DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1);
+    ASSERT_EQ(Kind::kInStack, location0.GetKind());
+    ASSERT_EQ(Kind::kConstant, location1.GetKind());
+    ASSERT_EQ(Kind::kInStack, location0.GetInternalKind());
+    ASSERT_EQ(Kind::kConstantLargeValue, location1.GetInternalKind());
+    ASSERT_EQ(0, location0.GetValue());
+    ASSERT_EQ(-2, location1.GetValue());
+
+    // Test that the inline info dex register map deduplicated to the same offset as the stack map
+    // one.
+    ASSERT_TRUE(stack_map.HasInlineInfo(encoding.stack_map.encoding));
+    InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+    EXPECT_EQ(inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding, 0),
+              stack_map.GetDexRegisterMapOffset(encoding.stack_map.encoding));
+  }
+}
+
 TEST(StackMapTest, TestNonLiveDexRegisters) {
   ArenaPool pool;
   ArenaAllocator arena(&pool);