Cache DexRegisterMaps when writing native debug info.

I might make the function more expensive in the future so I want
to make sure it gets called only the minimum number of times.

Change-Id: I1d09ecf1db7b54d28aaa11a152226d469f514fe7
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index eed032f..bddb054 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -173,6 +173,19 @@
       info_.WriteExprLoc(DW_AT_frame_base, expr);
       WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
 
+      // Decode dex register locations for all stack maps.
+      // It might be expensive, so do it just once and reuse the result.
+      std::vector<DexRegisterMap> dex_reg_maps;
+      if (mi->IsFromOptimizingCompiler()) {
+        const CodeInfo code_info(mi->compiled_method->GetVmapTable().data());
+        StackMapEncoding encoding = code_info.ExtractEncoding();
+        for (size_t s = 0; s < code_info.GetNumberOfStackMaps(); ++s) {
+          const StackMap& stack_map = code_info.GetStackMapAt(s, encoding);
+          dex_reg_maps.push_back(code_info.GetDexRegisterMapOf(
+              stack_map, encoding, dex_code->registers_size_));
+        }
+      }
+
       // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not
       // guarantee order or uniqueness so it is safer to iterate over them manually.
       // DecodeDebugLocalInfo might not also be available if there is no debug info.
@@ -187,7 +200,7 @@
           // Write the stack location of the parameter.
           const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
           const bool is64bitValue = false;
-          WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+          WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.low_pc);
         }
         arg_reg++;
         info_.EndTag();
@@ -206,7 +219,7 @@
           if (dex_code != nullptr) {
             // Write the stack location of the parameter.
             const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
-            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+            WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.low_pc);
           }
           arg_reg += is64bitValue ? 2 : 1;
           info_.EndTag();
@@ -229,8 +242,13 @@
             WriteName(var.name_);
             WriteLazyType(var.descriptor_);
             bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J';
-            WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc,
-                             var.start_address_, var.end_address_);
+            WriteRegLocation(mi,
+                             dex_reg_maps,
+                             var.reg_,
+                             is64bitValue,
+                             compilation_unit.low_pc,
+                             var.start_address_,
+                             var.end_address_);
             info_.EndTag();
           }
         }
@@ -424,12 +442,14 @@
   // The dex register might be valid only at some points and it might
   // move between machine registers and stack.
   void WriteRegLocation(const MethodDebugInfo* method_info,
+                        const std::vector<DexRegisterMap>& dex_register_maps,
                         uint16_t vreg,
                         bool is64bitValue,
                         uint32_t compilation_unit_low_pc,
                         uint32_t dex_pc_low = 0,
                         uint32_t dex_pc_high = 0xFFFFFFFF) {
     WriteDebugLocEntry(method_info,
+                       dex_register_maps,
                        vreg,
                        is64bitValue,
                        compilation_unit_low_pc,
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index 32f624a..c321b4b 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -85,29 +85,32 @@
 // The result will cover all ranges where the variable is in scope.
 // PCs corresponding to stackmap with dex register map are accurate,
 // all other PCs are best-effort only.
-std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
-                                                   uint16_t vreg,
-                                                   bool is64bitValue,
-                                                   uint32_t dex_pc_low,
-                                                   uint32_t dex_pc_high) {
+std::vector<VariableLocation> GetVariableLocations(
+    const MethodDebugInfo* method_info,
+    const std::vector<DexRegisterMap>& dex_register_maps,
+    uint16_t vreg,
+    bool is64bitValue,
+    uint32_t dex_pc_low,
+    uint32_t dex_pc_high) {
   std::vector<VariableLocation> variable_locations;
 
   // Get stack maps sorted by pc (they might not be sorted internally).
   const CodeInfo code_info(method_info->compiled_method->GetVmapTable().data());
   const StackMapEncoding encoding = code_info.ExtractEncoding();
-  std::map<uint32_t, StackMap> stack_maps;
+  std::map<uint32_t, uint32_t> stack_maps;  // low_pc -> stack_map_index.
   for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
     StackMap stack_map = code_info.GetStackMapAt(s, encoding);
     DCHECK(stack_map.IsValid());
     const uint32_t low_pc = method_info->low_pc + stack_map.GetNativePcOffset(encoding);
     DCHECK_LE(low_pc, method_info->high_pc);
-    stack_maps.emplace(low_pc, stack_map);
+    stack_maps.emplace(low_pc, s);
   }
 
   // Create entries for the requested register based on stack map data.
   for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
-    const StackMap& stack_map = it->second;
     const uint32_t low_pc = it->first;
+    const uint32_t stack_map_index = it->second;
+    const StackMap& stack_map = code_info.GetStackMapAt(stack_map_index, encoding);
     auto next_it = it;
     next_it++;
     const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
@@ -126,9 +129,9 @@
     // Find the location of the dex register.
     DexRegisterLocation reg_lo = DexRegisterLocation::None();
     DexRegisterLocation reg_hi = DexRegisterLocation::None();
-    if (stack_map.HasDexRegisterMap(encoding)) {
-      DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
-          stack_map, encoding, method_info->code_item->registers_size_);
+    DCHECK_LT(stack_map_index, dex_register_maps.size());
+    DexRegisterMap dex_register_map = dex_register_maps[stack_map_index];
+    if (dex_register_map.IsValid()) {
       reg_lo = dex_register_map.GetDexRegisterLocation(
           vreg, method_info->code_item->registers_size_, code_info, encoding);
       if (is64bitValue) {
@@ -159,6 +162,7 @@
 // The dex register might be valid only at some points and it might
 // move between machine registers and stack.
 static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
+                               const std::vector<DexRegisterMap>& dex_register_maps,
                                uint16_t vreg,
                                bool is64bitValue,
                                uint32_t compilation_unit_low_pc,
@@ -175,6 +179,7 @@
 
   std::vector<VariableLocation> variable_locations = GetVariableLocations(
       method_info,
+      dex_register_maps,
       vreg,
       is64bitValue,
       dex_pc_low,