Cache stack map encoding

Operations on CodeInfo and StackMap objects repeatedly read encoding
information from the MemoryRegion. Since these are 3-bit-loads of
values that never change, caching them can measurably reduce compile
times.

According to benchmarks, this patch saves 1-3% on armv7, 2-4% on x86,
and 0-1% on x64.

Change-Id: I46b197513601325d8bab562cc80100c00ec28a3b
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index a64071f..f8fc2a9 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -28,9 +28,10 @@
 
 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number,
                                                                   uint16_t number_of_dex_registers,
-                                                                  const CodeInfo& code_info) const {
+                                                                  const CodeInfo& code_info,
+                                                                  const StackMapEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
-      code_info.GetDexRegisterLocationCatalog();
+      code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
@@ -40,9 +41,10 @@
 
 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
                                                            uint16_t number_of_dex_registers,
-                                                           const CodeInfo& code_info) const {
+                                                           const CodeInfo& code_info,
+                                                           const StackMapEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
-      code_info.GetDexRegisterLocationCatalog();
+      code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
@@ -50,156 +52,43 @@
   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
 }
 
-// Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
-// this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
-static uint32_t LoadAt(MemoryRegion region,
-                       size_t number_of_bytes,
-                       size_t offset,
-                       bool check_max = false) {
+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);
-    if (check_max && value == 0xFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    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);
-    if (check_max && value == 0xFFFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    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));
+    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;
-    if (check_max && value == 0xFFFFFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    return (check_max && value == 0xFFFFFF) ? -1 : value;
   } else {
     DCHECK_EQ(number_of_bytes, 4u);
-    return region.LoadUnaligned<uint32_t>(offset);
+    return region_.LoadUnaligned<uint32_t>(offset);
   }
 }
 
-static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) {
+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);
+    region_.StoreUnaligned<uint8_t>(offset, value);
   } else if (number_of_bytes == 2u) {
-    region.StoreUnaligned<uint16_t>(offset, value);
+    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));
+    region_.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
+    region_.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
   } else {
-    region.StoreUnaligned<uint32_t>(offset, value);
+    region_.StoreUnaligned<uint32_t>(offset, value);
     DCHECK_EQ(number_of_bytes, 4u);
   }
 }
 
-uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
-  return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
-}
-
-void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
-  StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
-}
-
-uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
-  return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
-}
-
-void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
-  StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
-}
-
-uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
-  return LoadAt(region_,
-                info.NumberOfBytesForDexRegisterMap(),
-                info.ComputeStackMapDexRegisterMapOffset(),
-                /* check_max */ true);
-}
-
-void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
-  StoreAt(region_,
-          info.NumberOfBytesForDexRegisterMap(),
-          info.ComputeStackMapDexRegisterMapOffset(),
-          offset);
-}
-
-uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const {
-  if (!info.HasInlineInfo()) return kNoInlineInfo;
-  return LoadAt(region_,
-                info.NumberOfBytesForInlineInfo(),
-                info.ComputeStackMapInlineInfoOffset(),
-                /* check_max */ true);
-}
-
-void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) {
-  DCHECK(info.HasInlineInfo());
-  StoreAt(region_,
-          info.NumberOfBytesForInlineInfo(),
-          info.ComputeStackMapInlineInfoOffset(),
-          offset);
-}
-
-uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
-  return LoadAt(region_,
-                info.NumberOfBytesForRegisterMask(),
-                info.ComputeStackMapRegisterMaskOffset());
-}
-
-void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
-  StoreAt(region_,
-          info.NumberOfBytesForRegisterMask(),
-          info.ComputeStackMapRegisterMaskOffset(),
-          mask);
-}
-
-size_t StackMap::ComputeStackMapSizeInternal(size_t stack_mask_size,
-                                             size_t number_of_bytes_for_inline_info,
-                                             size_t number_of_bytes_for_dex_map,
-                                             size_t number_of_bytes_for_dex_pc,
-                                             size_t number_of_bytes_for_native_pc,
-                                             size_t number_of_bytes_for_register_mask) {
-  return stack_mask_size
-      + number_of_bytes_for_inline_info
-      + number_of_bytes_for_dex_map
-      + number_of_bytes_for_dex_pc
-      + number_of_bytes_for_native_pc
-      + number_of_bytes_for_register_mask;
-}
-
-size_t StackMap::ComputeStackMapSize(size_t stack_mask_size,
-                                     size_t inline_info_size,
-                                     size_t dex_register_map_size,
-                                     size_t dex_pc_max,
-                                     size_t native_pc_max,
-                                     size_t register_mask_max) {
-  return ComputeStackMapSizeInternal(
-      stack_mask_size,
-      inline_info_size == 0
-          ? 0
-            // + 1 to also encode kNoInlineInfo.
-          :  CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1),
-      // + 1 to also encode kNoDexRegisterMap.
-      CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1),
-      CodeInfo::EncodingSizeInBytes(dex_pc_max),
-      CodeInfo::EncodingSizeInBytes(native_pc_max),
-      CodeInfo::EncodingSizeInBytes(register_mask_max));
-}
-
-MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
-  return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
-}
-
 static void DumpRegisterMapping(std::ostream& os,
                                 size_t dex_register_num,
                                 DexRegisterLocation location,
@@ -216,6 +105,7 @@
                     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();
   Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
@@ -223,21 +113,26 @@
   indented_os << "Optimized CodeInfo (size=" << code_info_size
               << ", number_of_dex_registers=" << number_of_dex_registers
               << ", number_of_stack_maps=" << number_of_stack_maps
-              << ", has_inline_info=" << HasInlineInfo()
-              << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
-              << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
-              << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
-              << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
-              << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
+              << ", 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";
   // Display the Dex register location catalog.
-  GetDexRegisterLocationCatalog().Dump(indented_os, *this);
+  GetDexRegisterLocationCatalog(encoding).Dump(indented_os, *this);
   // Display stack maps along with (live) Dex register maps.
   if (dump_stack_maps) {
     for (size_t i = 0; i < number_of_stack_maps; ++i) {
-      StackMap stack_map = GetStackMapAt(i);
-      stack_map.Dump(
-          indented_os, *this, code_offset, number_of_dex_registers, " " + std::to_string(i));
+      StackMap stack_map = GetStackMapAt(i, encoding);
+      stack_map.Dump(indented_os,
+                     *this,
+                     encoding,
+                     code_offset,
+                     number_of_dex_registers,
+                     " " + std::to_string(i));
     }
   }
   // TODO: Dump the stack map's inline information? We need to know more from the caller:
@@ -245,9 +140,10 @@
 }
 
 void DexRegisterLocationCatalog::Dump(std::ostream& os, const CodeInfo& code_info) {
+  StackMapEncoding encoding = code_info.ExtractEncoding();
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
-  size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize();
+  size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
   Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   std::ostream indented_os(&indent_filter);
   indented_os
@@ -262,6 +158,7 @@
 void DexRegisterMap::Dump(std::ostream& os,
                           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.GetNumberOfDexRegisterLocationCatalogEntries();
   Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
@@ -271,7 +168,10 @@
     if (IsDexRegisterLive(j)) {
       size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
           j, number_of_dex_registers, number_of_location_catalog_entries);
-      DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, code_info);
+      DexRegisterLocation location = GetDexRegisterLocation(j,
+                                                            number_of_dex_registers,
+                                                            code_info,
+                                                            encoding);
       DumpRegisterMapping(
           indented_os, j, location, "v",
           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
@@ -281,6 +181,7 @@
 
 void StackMap::Dump(std::ostream& os,
                     const CodeInfo& code_info,
+                    const StackMapEncoding& encoding,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     const std::string& header_suffix) const {
@@ -288,21 +189,22 @@
   std::ostream indented_os(&indent_filter);
   indented_os << "StackMap" << header_suffix
               << std::hex
-              << " [native_pc=0x" << code_offset + GetNativePcOffset(code_info) << "]"
-              << " (dex_pc=0x" << GetDexPc(code_info)
-              << ", native_pc_offset=0x" << GetNativePcOffset(code_info)
-              << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(code_info)
-              << ", inline_info_offset=0x" << GetInlineDescriptorOffset(code_info)
-              << ", register_mask=0x" << GetRegisterMask(code_info)
+              << " [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)
               << std::dec
               << ", stack_mask=0b";
-  MemoryRegion stack_mask = GetStackMask(code_info);
+  MemoryRegion stack_mask = GetStackMask(encoding);
   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
     indented_os << stack_mask.LoadBit(e - i - 1);
   }
   indented_os << ")\n";
-  if (HasDexRegisterMap(code_info)) {
-    DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(*this, number_of_dex_registers);
+  if (HasDexRegisterMap(encoding)) {
+    DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
+        *this, encoding, number_of_dex_registers);
     dex_register_map.Dump(os, code_info, number_of_dex_registers);
   }
 }
@@ -321,8 +223,9 @@
                 << ", method_index=0x" << GetMethodIndexAtDepth(i)
                 << ")\n";
     if (HasDexRegisterMapAtDepth(i)) {
+      StackMapEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
-          code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]);
+          code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
       dex_register_map.Dump(indented_os, code_info, number_of_dex_registers[i]);
     }
   }