[optimizing] Don't record None locations in the stack maps.

- moved environment recording from code generator to stack map stream
- added creation/loading factory methods for the DexRegisterMap (hides
internal details)
- added new tests

Change-Id: Ic8b6d044f0d8255c6759c19a41df332ef37876fe
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index a6ab208..9ebf887 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -577,142 +577,42 @@
   pc_info.native_pc = GetAssembler()->CodeSize();
   pc_infos_.Add(pc_info);
 
-  // Populate stack map information.
-
+  uint32_t inlining_depth = 0;
   if (instruction == nullptr) {
     // For stack overflow checks.
-    stack_map_stream_.AddStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, 0);
-    return;
-  }
+    stack_map_stream_.RecordEnvironment(
+       /* environment */ nullptr,
+       /* environment_size */ 0,
+       /* locations */ nullptr,
+       dex_pc,
+       pc_info.native_pc,
+       /* register_mask */ 0,
+       inlining_depth);
+  } else {
+    LocationSummary* locations = instruction->GetLocations();
+    HEnvironment* environment = instruction->GetEnvironment();
+    size_t environment_size = instruction->EnvironmentSize();
 
-  LocationSummary* locations = instruction->GetLocations();
-  HEnvironment* environment = instruction->GetEnvironment();
-
-  size_t environment_size = instruction->EnvironmentSize();
-
-  size_t inlining_depth = 0;
-  uint32_t register_mask = locations->GetRegisterMask();
-  if (locations->OnlyCallsOnSlowPath()) {
-    // In case of slow path, we currently set the location of caller-save registers
-    // to register (instead of their stack location when pushed before the slow-path
-    // call). Therefore register_mask contains both callee-save and caller-save
-    // registers that hold objects. We must remove the caller-save from the mask, since
-    // they will be overwritten by the callee.
-    register_mask &= core_callee_save_mask_;
-  }
-  // The register mask must be a subset of callee-save registers.
-  DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
-  stack_map_stream_.AddStackMapEntry(
-      dex_pc, pc_info.native_pc, register_mask,
-      locations->GetStackMask(), environment_size, inlining_depth);
-
-  // Walk over the environment, and record the location of dex registers.
-  for (size_t i = 0; i < environment_size; ++i) {
-    HInstruction* current = environment->GetInstructionAt(i);
-    if (current == nullptr) {
-      stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
-      continue;
+    uint32_t register_mask = locations->GetRegisterMask();
+    if (locations->OnlyCallsOnSlowPath()) {
+      // In case of slow path, we currently set the location of caller-save registers
+      // to register (instead of their stack location when pushed before the slow-path
+      // call). Therefore register_mask contains both callee-save and caller-save
+      // registers that hold objects. We must remove the caller-save from the mask, since
+      // they will be overwritten by the callee.
+      register_mask &= core_callee_save_mask_;
     }
+    // The register mask must be a subset of callee-save registers.
+    DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
 
-    Location location = locations->GetEnvironmentAt(i);
-    switch (location.GetKind()) {
-      case Location::kConstant: {
-        DCHECK_EQ(current, location.GetConstant());
-        if (current->IsLongConstant()) {
-          int64_t value = current->AsLongConstant()->GetValue();
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant,
-                                                Low32Bits(value));
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant,
-                                                High32Bits(value));
-          ++i;
-          DCHECK_LT(i, environment_size);
-        } else if (current->IsDoubleConstant()) {
-          int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue());
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant,
-                                                Low32Bits(value));
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant,
-                                                High32Bits(value));
-          ++i;
-          DCHECK_LT(i, environment_size);
-        } else if (current->IsIntConstant()) {
-          int32_t value = current->AsIntConstant()->GetValue();
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
-        } else if (current->IsNullConstant()) {
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
-        } else {
-          DCHECK(current->IsFloatConstant());
-          int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
-        }
-        break;
-      }
-
-      case Location::kStackSlot: {
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
-                                              location.GetStackIndex());
-        break;
-      }
-
-      case Location::kDoubleStackSlot: {
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
-                                              location.GetStackIndex());
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
-                                              location.GetHighStackIndex(kVRegSize));
-        ++i;
-        DCHECK_LT(i, environment_size);
-        break;
-      }
-
-      case Location::kRegister : {
-        int id = location.reg();
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
-        if (current->GetType() == Primitive::kPrimLong) {
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
-          ++i;
-          DCHECK_LT(i, environment_size);
-        }
-        break;
-      }
-
-      case Location::kFpuRegister : {
-        int id = location.reg();
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
-        if (current->GetType() == Primitive::kPrimDouble) {
-          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
-          ++i;
-          DCHECK_LT(i, environment_size);
-        }
-        break;
-      }
-
-      case Location::kFpuRegisterPair : {
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister,
-                                              location.low());
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister,
-                                              location.high());
-        ++i;
-        DCHECK_LT(i, environment_size);
-        break;
-      }
-
-      case Location::kRegisterPair : {
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister,
-                                              location.low());
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister,
-                                              location.high());
-        ++i;
-        DCHECK_LT(i, environment_size);
-        break;
-      }
-
-      case Location::kInvalid: {
-        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
-        break;
-      }
-
-      default:
-        LOG(FATAL) << "Unexpected kind " << location.GetKind();
-    }
+    // Populate stack map information.
+    stack_map_stream_.RecordEnvironment(environment,
+                                        environment_size,
+                                        locations,
+                                        dex_pc,
+                                        pc_info.native_pc,
+                                        register_mask,
+                                        inlining_depth);
   }
 }
 
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index b8f4572..b574148 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -29,8 +29,6 @@
 
 namespace art {
 
-static size_t constexpr kVRegSize = 4;
-
 // Binary encoding of 2^32 for type double.
 static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000);
 // Binary encoding of 2^31 for type double.
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 863bab2..3168801 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -20,6 +20,7 @@
 #include "base/bit_vector.h"
 #include "base/value_object.h"
 #include "memory_region.h"
+#include "nodes.h"
 #include "stack_map.h"
 #include "utils/growable_array.h"
 
@@ -32,8 +33,9 @@
 class StackMapStream : public ValueObject {
  public:
   explicit StackMapStream(ArenaAllocator* allocator)
-      : stack_maps_(allocator, 10),
-        dex_register_maps_(allocator, 10 * 4),
+      : allocator_(allocator),
+        stack_maps_(allocator, 10),
+        dex_register_locations_(allocator, 10 * 4),
         inline_infos_(allocator, 2),
         stack_mask_max_(-1),
         number_of_stack_maps_with_inline_info_(0) {}
@@ -52,8 +54,9 @@
     BitVector* sp_mask;
     uint32_t num_dex_registers;
     uint8_t inlining_depth;
-    size_t dex_register_maps_start_index;
+    size_t dex_register_locations_start_index;
     size_t inline_infos_start_index;
+    BitVector* live_dex_registers_mask;
   };
 
   struct InlineInfoEntry {
@@ -65,7 +68,8 @@
                         uint32_t register_mask,
                         BitVector* sp_mask,
                         uint32_t num_dex_registers,
-                        uint8_t inlining_depth) {
+                        uint8_t inlining_depth,
+                        BitVector* live_dex_registers_mask) {
     StackMapEntry entry;
     entry.dex_pc = dex_pc;
     entry.native_pc_offset = native_pc_offset;
@@ -73,8 +77,9 @@
     entry.sp_mask = sp_mask;
     entry.num_dex_registers = num_dex_registers;
     entry.inlining_depth = inlining_depth;
-    entry.dex_register_maps_start_index = dex_register_maps_.Size();
+    entry.dex_register_locations_start_index = dex_register_locations_.Size();
     entry.inline_infos_start_index = inline_infos_.Size();
+    entry.live_dex_registers_mask = live_dex_registers_mask;
     stack_maps_.Add(entry);
 
     if (sp_mask != nullptr) {
@@ -85,11 +90,146 @@
     }
   }
 
-  void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
-    // Ensure we only use non-compressed location kind at this stage.
-    DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
-        << DexRegisterLocation::PrettyDescriptor(kind);
-    dex_register_maps_.Add(DexRegisterLocation(kind, value));
+  void RecordEnvironment(HEnvironment* environment,
+                         size_t environment_size,
+                         LocationSummary* locations,
+                         uint32_t dex_pc,
+                         uint32_t native_pc,
+                         uint32_t register_mask,
+                         uint32_t inlining_depth) {
+    if (environment == nullptr) {
+      // For stack overflow checks.
+      AddStackMapEntry(dex_pc, native_pc, 0, 0, 0, inlining_depth, nullptr);
+      return;
+    }
+
+    BitVector* live_dex_registers_mask = new (allocator_) ArenaBitVector(allocator_, 0, true);
+
+    AddStackMapEntry(
+        dex_pc, native_pc, register_mask,
+        locations->GetStackMask(), environment_size, inlining_depth, live_dex_registers_mask);
+
+    // Walk over the environment, and record the location of dex registers.
+    for (size_t i = 0; i < environment_size; ++i) {
+      HInstruction* current = environment->GetInstructionAt(i);
+      if (current == nullptr) {
+        // No need to store anything, the `live_dex_registers_mask` will hold the
+        // information that this register is not live.
+        continue;
+      }
+
+      Location location = locations->GetEnvironmentAt(i);
+      switch (location.GetKind()) {
+        case Location::kConstant: {
+          DCHECK_EQ(current, location.GetConstant());
+          if (current->IsLongConstant()) {
+            // TODO: Consider moving setting the bit in AddDexRegisterEntry to avoid
+            // doing it manually here.
+            live_dex_registers_mask->SetBit(i);
+            live_dex_registers_mask->SetBit(i + 1);
+            int64_t value = current->AsLongConstant()->GetValue();
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value));
+            ++i;
+            DCHECK_LT(i, environment_size);
+          } else if (current->IsDoubleConstant()) {
+            live_dex_registers_mask->SetBit(i);
+            live_dex_registers_mask->SetBit(i + 1);
+            int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue());
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value));
+            ++i;
+            DCHECK_LT(i, environment_size);
+          } else if (current->IsIntConstant()) {
+            live_dex_registers_mask->SetBit(i);
+            int32_t value = current->AsIntConstant()->GetValue();
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
+          } else if (current->IsNullConstant()) {
+            live_dex_registers_mask->SetBit(i);
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
+          } else {
+            DCHECK(current->IsFloatConstant()) << current->DebugName();
+            live_dex_registers_mask->SetBit(i);
+            int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
+          }
+          break;
+        }
+
+        case Location::kStackSlot: {
+          live_dex_registers_mask->SetBit(i);
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
+                              location.GetStackIndex());
+          break;
+        }
+
+        case Location::kDoubleStackSlot: {
+          live_dex_registers_mask->SetBit(i);
+          live_dex_registers_mask->SetBit(i + 1);
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
+                              location.GetHighStackIndex(kVRegSize));
+          ++i;
+          DCHECK_LT(i, environment_size);
+          break;
+        }
+
+        case Location::kRegister : {
+          live_dex_registers_mask->SetBit(i);
+          int id = location.reg();
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
+          if (current->GetType() == Primitive::kPrimLong) {
+            live_dex_registers_mask->SetBit(i + 1);
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
+            ++i;
+            DCHECK_LT(i, environment_size);
+          }
+          break;
+        }
+
+        case Location::kFpuRegister : {
+          live_dex_registers_mask->SetBit(i);
+          int id = location.reg();
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
+          if (current->GetType() == Primitive::kPrimDouble) {
+            live_dex_registers_mask->SetBit(i + 1);
+            AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
+            ++i;
+            DCHECK_LT(i, environment_size);
+          }
+          break;
+        }
+
+        case Location::kFpuRegisterPair : {
+          live_dex_registers_mask->SetBit(i);
+          live_dex_registers_mask->SetBit(i + 1);
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.low());
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.high());
+          ++i;
+          DCHECK_LT(i, environment_size);
+          break;
+        }
+
+        case Location::kRegisterPair : {
+          live_dex_registers_mask->SetBit(i);
+          live_dex_registers_mask->SetBit(i + 1);
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.low());
+          AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.high());
+          ++i;
+          DCHECK_LT(i, environment_size);
+          break;
+        }
+
+        case Location::kInvalid: {
+          // No need to store anything, the `live_dex_registers_mask` will hold the
+          // information that this register is not live.
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected kind " << location.GetKind();
+      }
+    }
   }
 
   void AddInlineInfoEntry(uint32_t method_index) {
@@ -118,22 +258,26 @@
   // Compute the size of the Dex register map of `entry`.
   size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
     size_t size = DexRegisterMap::kFixedSize;
-    for (size_t j = 0; j < entry.num_dex_registers; ++j) {
-      DexRegisterLocation dex_register_location =
-          dex_register_maps_.Get(entry.dex_register_maps_start_index + j);
-      size += DexRegisterMap::EntrySize(dex_register_location);
+    // Add the bit mask for the dex register liveness.
+    size += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
+    for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+         dex_register_number < entry.num_dex_registers;
+         ++dex_register_number) {
+      if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+        DexRegisterLocation dex_register_location = dex_register_locations_.Get(
+            entry.dex_register_locations_start_index + index_in_dex_register_locations);
+        size += DexRegisterMap::EntrySize(dex_register_location);
+        index_in_dex_register_locations++;
+      }
     }
     return size;
   }
 
   // Compute the size of all the Dex register maps.
   size_t ComputeDexRegisterMapsSize() const {
-    size_t size = stack_maps_.Size() * DexRegisterMap::kFixedSize;
-    // The size of each register location depends on the type of
-    // the entry.
-    for (size_t i = 0, e = dex_register_maps_.Size(); i < e; ++i) {
-      DexRegisterLocation entry = dex_register_maps_.Get(i);
-      size += DexRegisterMap::EntrySize(entry);
+    size_t size = 0;
+    for (size_t i = 0; i < stack_maps_.Size(); ++i) {
+      size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
     }
     return size;
   }
@@ -161,7 +305,7 @@
     size_t stack_mask_size = ComputeStackMaskSize();
     uint8_t* memory_start = region.start();
 
-    MemoryRegion dex_register_maps_region = region.Subregion(
+    MemoryRegion dex_register_locations_region = region.Subregion(
       ComputeDexRegisterMapsStart(),
       ComputeDexRegisterMapsSize());
 
@@ -189,7 +333,7 @@
       if (entry.num_dex_registers != 0) {
         // Set the Dex register map.
         MemoryRegion register_region =
-            dex_register_maps_region.Subregion(
+            dex_register_locations_region.Subregion(
                 next_dex_register_map_offset,
                 ComputeDexRegisterMapSize(entry));
         next_dex_register_map_offset += register_region.size();
@@ -198,11 +342,20 @@
 
         // Offset in `dex_register_map` where to store the next register entry.
         size_t offset = DexRegisterMap::kFixedSize;
-        for (size_t j = 0; j < entry.num_dex_registers; ++j) {
-          DexRegisterLocation dex_register_location =
-              dex_register_maps_.Get(entry.dex_register_maps_start_index + j);
-          dex_register_map.SetRegisterInfo(offset, dex_register_location);
-          offset += DexRegisterMap::EntrySize(dex_register_location);
+        dex_register_map.SetLiveBitMask(offset,
+                                        entry.num_dex_registers,
+                                        *entry.live_dex_registers_mask);
+        offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
+        for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+             dex_register_number < entry.num_dex_registers;
+             ++dex_register_number) {
+          if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+            DexRegisterLocation dex_register_location = dex_register_locations_.Get(
+                entry.dex_register_locations_start_index + index_in_dex_register_locations);
+            dex_register_map.SetRegisterInfo(offset, dex_register_location);
+            offset += DexRegisterMap::EntrySize(dex_register_location);
+            ++index_in_dex_register_locations;
+          }
         }
         // Ensure we reached the end of the Dex registers region.
         DCHECK_EQ(offset, register_region.size());
@@ -232,12 +385,24 @@
   }
 
  private:
+  void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
+    // Ensure we only use non-compressed location kind at this stage.
+    DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
+        << DexRegisterLocation::PrettyDescriptor(kind);
+    dex_register_locations_.Add(DexRegisterLocation(kind, value));
+  }
+
+  ArenaAllocator* allocator_;
   GrowableArray<StackMapEntry> stack_maps_;
-  GrowableArray<DexRegisterLocation> dex_register_maps_;
+  GrowableArray<DexRegisterLocation> dex_register_locations_;
   GrowableArray<InlineInfoEntry> inline_infos_;
   int stack_mask_max_;
   size_t number_of_stack_maps_with_inline_info_;
 
+  ART_FRIEND_TEST(StackMapTest, Test1);
+  ART_FRIEND_TEST(StackMapTest, Test2);
+  ART_FRIEND_TEST(StackMapTest, TestNonLiveDexRegisters);
+
   DISALLOW_COPY_AND_ASSIGN(StackMapStream);
 };
 
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 3a5f806..4606bd6 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -31,19 +31,17 @@
   return true;
 }
 
-static size_t ComputeDexRegisterMapSize(const DexRegisterMap& dex_registers,
-                                        size_t number_of_dex_registers) {
-  return dex_registers.FindLocationOffset(number_of_dex_registers);
-}
-
 TEST(StackMapTest, Test1) {
   ArenaPool pool;
   ArenaAllocator arena(&pool);
   StackMapStream stream(&arena);
 
   ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector live_registers_mask(&arena, 0, true);
+  live_registers_mask.SetBit(0);
+  live_registers_mask.SetBit(1);
   size_t number_of_dex_registers = 2;
-  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0, &live_registers_mask);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, 0);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2);
 
@@ -68,10 +66,9 @@
 
   ASSERT_TRUE(stack_map.HasDexRegisterMap());
   DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-  ASSERT_EQ(6u, dex_registers.Size());
-  ASSERT_EQ(6u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers));
-  DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0);
-  DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1);
+  ASSERT_EQ(7u, dex_registers.Size());
+  DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0, number_of_dex_registers);
+  DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1, number_of_dex_registers);
   ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetKind());
   ASSERT_EQ(DexRegisterLocation::Kind::kConstant, location1.GetKind());
   ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetInternalKind());
@@ -91,7 +88,10 @@
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
   size_t number_of_dex_registers = 2;
-  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2);
+  ArenaBitVector live_registers_mask1(&arena, 0, true);
+  live_registers_mask1.SetBit(0);
+  live_registers_mask1.SetBit(1);
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2, &live_registers_mask1);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, 0);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2);
   stream.AddInlineInfoEntry(42);
@@ -100,7 +100,10 @@
   ArenaBitVector sp_mask2(&arena, 0, true);
   sp_mask2.SetBit(3);
   sp_mask1.SetBit(8);
-  stream.AddStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0);
+  ArenaBitVector live_registers_mask2(&arena, 0, true);
+  live_registers_mask2.SetBit(0);
+  live_registers_mask2.SetBit(1);
+  stream.AddStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0, &live_registers_mask2);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, 18);
   stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, 3);
 
@@ -128,10 +131,11 @@
     ASSERT_TRUE(stack_map.HasDexRegisterMap());
     DexRegisterMap dex_registers =
         code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-    ASSERT_EQ(6u, dex_registers.Size());
-    ASSERT_EQ(6u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers));
-    DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0);
-    DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1);
+    ASSERT_EQ(7u, dex_registers.Size());
+    DexRegisterLocation location0 =
+        dex_registers.GetLocationKindAndValue(0, number_of_dex_registers);
+    DexRegisterLocation location1 =
+        dex_registers.GetLocationKindAndValue(1, number_of_dex_registers);
     ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetKind());
     ASSERT_EQ(DexRegisterLocation::Kind::kConstant, location1.GetKind());
     ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetInternalKind());
@@ -161,10 +165,11 @@
     ASSERT_TRUE(stack_map.HasDexRegisterMap());
     DexRegisterMap dex_registers =
         code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-    ASSERT_EQ(2u, dex_registers.Size());
-    ASSERT_EQ(2u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers));
-    DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0);
-    DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1);
+    ASSERT_EQ(3u, dex_registers.Size());
+    DexRegisterLocation location0 =
+        dex_registers.GetLocationKindAndValue(0, number_of_dex_registers);
+    DexRegisterLocation location1 =
+        dex_registers.GetLocationKindAndValue(1, number_of_dex_registers);
     ASSERT_EQ(DexRegisterLocation::Kind::kInRegister, location0.GetKind());
     ASSERT_EQ(DexRegisterLocation::Kind::kInFpuRegister, location1.GetKind());
     ASSERT_EQ(DexRegisterLocation::Kind::kInRegister, location0.GetInternalKind());
@@ -176,4 +181,33 @@
   }
 }
 
+TEST(StackMapTest, TestNonLiveDexRegisters) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  StackMapStream stream(&arena);
+
+  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector live_registers_mask(&arena, 0, true);
+  live_registers_mask.SetBit(1);
+  uint32_t number_of_dex_registers = 2;
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0, &live_registers_mask);
+  stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2);
+
+  size_t size = stream.ComputeNeededSize();
+  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  MemoryRegion region(memory, size);
+  stream.FillIn(region);
+
+  CodeInfo code_info(region);
+  StackMap stack_map = code_info.GetStackMapAt(0);
+  ASSERT_TRUE(stack_map.HasDexRegisterMap());
+  DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2);
+  ASSERT_EQ(DexRegisterLocation::Kind::kNone,
+            dex_registers.GetLocationKind(0, number_of_dex_registers));
+  ASSERT_EQ(DexRegisterLocation::Kind::kConstant,
+            dex_registers.GetLocationKind(1, number_of_dex_registers));
+  ASSERT_EQ(-2, dex_registers.GetConstant(1, number_of_dex_registers));
+  ASSERT_FALSE(stack_map.HasInlineInfo());
+}
+
 }  // namespace art
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 9512376..344d2b5 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1084,9 +1084,13 @@
       if (stack_map.HasDexRegisterMap()) {
         DexRegisterMap dex_register_map =
             code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+        // TODO: Display the bit mask of live Dex registers.
         for (size_t j = 0; j < number_of_dex_registers; ++j) {
-          DexRegisterLocation location = dex_register_map.GetLocationKindAndValue(j);
-          DumpRegisterMapping(os, j, location.GetInternalKind(), location.GetValue());
+          if (dex_register_map.IsDexRegisterLive(j)) {
+            DexRegisterLocation location =
+                dex_register_map.GetLocationKindAndValue(j, number_of_dex_registers);
+            DumpRegisterMapping(os, j, location.GetInternalKind(), location.GetValue());
+          }
         }
       }
     }
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 893ab11..0ec0295 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -66,14 +66,16 @@
     mirror::ArtMethod* m = GetMethod();
     CodeInfo code_info = m->GetOptimizedCodeInfo();
     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+    uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
     DexRegisterMap dex_register_map =
-        code_info.GetDexRegisterMapOf(stack_map, m->GetCodeItem()->registers_size_);
+        code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
     MemoryRegion stack_mask = stack_map.GetStackMask();
     uint32_t register_mask = stack_map.GetRegisterMask();
     for (int i = 0; i < number_of_references; ++i) {
       int reg = registers[i];
       CHECK(reg < m->GetCodeItem()->registers_size_);
-      DexRegisterLocation location = dex_register_map.GetLocationKindAndValue(reg);
+      DexRegisterLocation location =
+          dex_register_map.GetLocationKindAndValue(reg, number_of_dex_registers);
       switch (location.GetKind()) {
         case DexRegisterLocation::Kind::kNone:
           // Not set, should not be a reference.
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 47b85ad..2d688ee 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -202,30 +202,33 @@
   DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
                                                     // its instructions?
   DCHECK_LT(vreg, code_item->registers_size_);
+  uint16_t number_of_dex_registers = code_item->registers_size_;
   DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, code_item->registers_size_);
-  DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg);
+      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+  DexRegisterLocation::Kind location_kind =
+      dex_register_map.GetLocationKind(vreg, number_of_dex_registers);
   switch (location_kind) {
     case DexRegisterLocation::Kind::kInStack: {
-      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers);
       const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
       *val = *reinterpret_cast<const uint32_t*>(addr);
       return true;
     }
     case DexRegisterLocation::Kind::kInRegister:
     case DexRegisterLocation::Kind::kInFpuRegister: {
-      uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+      uint32_t reg = dex_register_map.GetMachineRegister(vreg, number_of_dex_registers);
       return GetRegisterIfAccessible(reg, kind, val);
     }
     case DexRegisterLocation::Kind::kConstant:
-      *val = dex_register_map.GetConstant(vreg);
+      *val = dex_register_map.GetConstant(vreg, number_of_dex_registers);
       return true;
     case DexRegisterLocation::Kind::kNone:
       return false;
     default:
       LOG(FATAL)
           << "Unexpected location kind"
-          << DexRegisterLocation::PrettyDescriptor(dex_register_map.GetLocationInternalKind(vreg));
+          << DexRegisterLocation::PrettyDescriptor(
+                dex_register_map.GetLocationInternalKind(vreg, number_of_dex_registers));
       UNREACHABLE();
   }
 }
@@ -388,21 +391,23 @@
   const DexFile::CodeItem* code_item = m->GetCodeItem();
   DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
                                                     // its instructions?
-  DCHECK_LT(vreg, code_item->registers_size_);
+  uint16_t number_of_dex_registers = code_item->registers_size_;
+  DCHECK_LT(vreg, number_of_dex_registers);
   DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, code_item->registers_size_);
-  DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg);
+      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+  DexRegisterLocation::Kind location_kind =
+      dex_register_map.GetLocationKind(vreg, number_of_dex_registers);
   uint32_t dex_pc = m->ToDexPc(cur_quick_frame_pc_, false);
   switch (location_kind) {
     case DexRegisterLocation::Kind::kInStack: {
-      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers);
       uint8_t* addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + offset;
       *reinterpret_cast<uint32_t*>(addr) = new_value;
       return true;
     }
     case DexRegisterLocation::Kind::kInRegister:
     case DexRegisterLocation::Kind::kInFpuRegister: {
-      uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+      uint32_t reg = dex_register_map.GetMachineRegister(vreg, number_of_dex_registers);
       return SetRegisterIfAccessible(reg, new_value, kind);
     }
     case DexRegisterLocation::Kind::kConstant:
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 8ebafc5..0db589f 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -31,6 +31,9 @@
 // Word alignment required on ARM, in bytes.
 static constexpr size_t kWordAlignment = 4;
 
+// Size of Dex virtual registers.
+static size_t constexpr kVRegSize = 4;
+
 /**
  * Classes in the following file are wrapper on stack map information backed
  * by a MemoryRegion. As such they read and write to the region, they don't have
@@ -191,6 +194,10 @@
   DexRegisterLocation(Kind kind, int32_t value)
       : kind_(kind), value_(value) {}
 
+  static DexRegisterLocation None() {
+    return DexRegisterLocation(Kind::kNone, 0);
+  }
+
   // Get the "surface" kind of the location, i.e., the one that doesn't
   // include any value with a "large" qualifier.
   Kind GetKind() const {
@@ -211,8 +218,8 @@
 /**
  * Information on dex register values for a specific PC. The information is
  * of the form:
- * [location_kind, register_value]+.
- * either on 1 or 5 bytes (see art::DexRegisterLocation::Kind).
+ * [live_bit_mask, DexRegisterLocation+].
+ * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
  */
 class DexRegisterMap {
  public:
@@ -221,6 +228,18 @@
   // Short (compressed) location, fitting on one byte.
   typedef uint8_t ShortLocation;
 
+  static size_t LiveBitMaskSize(uint16_t number_of_dex_registers) {
+    return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
+  }
+
+  void SetLiveBitMask(size_t offset,
+                      uint16_t number_of_dex_registers,
+                      const BitVector& live_dex_registers_mask) {
+    for (uint16_t i = 0; i < number_of_dex_registers; i++) {
+      region_.StoreBit(offset + i, live_dex_registers_mask.IsBitSet(i));
+    }
+  }
+
   void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
     DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
     int32_t value = dex_register_location.GetValue();
@@ -256,39 +275,63 @@
     }
   }
 
-  // Find the offset of the Dex register location number `dex_register_index`.
-  size_t FindLocationOffset(uint16_t dex_register_index) const {
+  bool IsDexRegisterLive(uint16_t dex_register_index) const {
     size_t offset = kFixedSize;
+    return region_.LoadBit(offset + dex_register_index);
+  }
+
+  static constexpr size_t kNoDexRegisterLocationOffset = -1;
+
+  static size_t GetDexRegisterMapLocationsOffset(uint16_t number_of_dex_registers) {
+    return kLiveBitMaskOffset + LiveBitMaskSize(number_of_dex_registers);
+  }
+
+  // Find the offset of the Dex register location number `dex_register_index`.
+  size_t FindLocationOffset(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
+    if (!IsDexRegisterLive(dex_register_index)) return kNoDexRegisterLocationOffset;
+    size_t offset = GetDexRegisterMapLocationsOffset(number_of_dex_registers);
     // Skip the first `dex_register_index - 1` entries.
     for (uint16_t i = 0; i < dex_register_index; ++i) {
-      // Read the first next byte and inspect its first 3 bits to decide
-      // whether it is a short or a large location.
-      DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
-      if (DexRegisterLocation::IsShortLocationKind(kind)) {
-        // Short location.  Skip the current byte.
-        offset += SingleShortEntrySize();
-      } else {
-        // Large location.  Skip the 5 next bytes.
-        offset += SingleLargeEntrySize();
+      if (IsDexRegisterLive(i)) {
+        // Read the first next byte and inspect its first 3 bits to decide
+        // whether it is a short or a large location.
+        DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
+        if (DexRegisterLocation::IsShortLocationKind(kind)) {
+          // Short location.  Skip the current byte.
+          offset += SingleShortEntrySize();
+        } else {
+          // Large location.  Skip the 5 next bytes.
+          offset += SingleLargeEntrySize();
+        }
       }
     }
     return offset;
   }
 
   // Get the surface kind.
-  DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index) const {
-    return DexRegisterLocation::ConvertToSurfaceKind(GetLocationInternalKind(dex_register_index));
+  DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index,
+                                            uint16_t number_of_dex_registers) const {
+    return IsDexRegisterLive(dex_register_index)
+        ? DexRegisterLocation::ConvertToSurfaceKind(
+              GetLocationInternalKind(dex_register_index, number_of_dex_registers))
+        : DexRegisterLocation::Kind::kNone;
   }
 
   // Get the internal kind.
-  DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index) const {
-    size_t offset = FindLocationOffset(dex_register_index);
-    return ExtractKindAtOffset(offset);
+  DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index,
+                                                    uint16_t number_of_dex_registers) const {
+    return IsDexRegisterLive(dex_register_index)
+        ? ExtractKindAtOffset(FindLocationOffset(dex_register_index, number_of_dex_registers))
+        : DexRegisterLocation::Kind::kNone;
   }
 
   // TODO: Rename as GetDexRegisterLocation?
-  DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index) const {
-    size_t offset = FindLocationOffset(dex_register_index);
+  DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index,
+                                              uint16_t number_of_dex_registers) const {
+    if (!IsDexRegisterLive(dex_register_index)) {
+      return DexRegisterLocation::None();
+    }
+    size_t offset = FindLocationOffset(dex_register_index, number_of_dex_registers);
     // Read the first byte and inspect its first 3 bits to get the location.
     ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
     DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
@@ -311,21 +354,25 @@
     }
   }
 
-  int32_t GetStackOffsetInBytes(uint16_t dex_register_index) const {
-    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
+  int32_t GetStackOffsetInBytes(uint16_t dex_register_index,
+                                uint16_t number_of_dex_registers) const {
+    DexRegisterLocation location =
+        GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
     DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
     // GetLocationKindAndValue returns the offset in bytes.
     return location.GetValue();
   }
 
-  int32_t GetConstant(uint16_t dex_register_index) const {
-    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
+  int32_t GetConstant(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
+    DexRegisterLocation location =
+        GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
     DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
     return location.GetValue();
   }
 
-  int32_t GetMachineRegister(uint16_t dex_register_index) const {
-    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
+  int32_t GetMachineRegister(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
+    DexRegisterLocation location =
+        GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
     DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
            || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
         << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
@@ -405,7 +452,8 @@
     return region_.size();
   }
 
-  static constexpr int kFixedSize = 0;
+  static constexpr int kLiveBitMaskOffset = 0;
+  static constexpr int kFixedSize = kLiveBitMaskOffset;
 
  private:
   // Width of the kind "field" in a short location, in bits.
@@ -428,6 +476,8 @@
   static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
     uint8_t kind = (location >> kKindOffset) & kKindMask;
     DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
+    // We do not encode kNone locations in the stack map.
+    DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
     return static_cast<DexRegisterLocation::Kind>(kind);
   }
 
@@ -678,21 +728,28 @@
     // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
     // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
     // yet built.  Try to factor common code.
-    size_t offset = origin + DexRegisterMap::kFixedSize;
+    size_t offset =
+        origin + DexRegisterMap::GetDexRegisterMapLocationsOffset(number_of_dex_registers);
+
+    // Create a temporary DexRegisterMap to be able to call DexRegisterMap.IsDexRegisterLive.
+    DexRegisterMap only_live_mask(MemoryRegion(region_.Subregion(origin, offset - origin)));
+
     // Skip the first `number_of_dex_registers - 1` entries.
     for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
-      // Read the first next byte and inspect its first 3 bits to decide
-      // whether it is a short or a large location.
-      DexRegisterMap::ShortLocation first_byte =
-          region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
-      DexRegisterLocation::Kind kind =
-          DexRegisterMap::ExtractKindFromShortLocation(first_byte);
-      if (DexRegisterLocation::IsShortLocationKind(kind)) {
-        // Short location.  Skip the current byte.
-        offset += DexRegisterMap::SingleShortEntrySize();
-      } else {
-        // Large location.  Skip the 5 next bytes.
-        offset += DexRegisterMap::SingleLargeEntrySize();
+      if (only_live_mask.IsDexRegisterLive(i)) {
+        // Read the first next byte and inspect its first 3 bits to decide
+        // whether it is a short or a large location.
+        DexRegisterMap::ShortLocation first_byte =
+            region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
+        DexRegisterLocation::Kind kind =
+            DexRegisterMap::ExtractKindFromShortLocation(first_byte);
+        if (DexRegisterLocation::IsShortLocationKind(kind)) {
+          // Short location.  Skip the current byte.
+          offset += DexRegisterMap::SingleShortEntrySize();
+        } else {
+          // Large location.  Skip the 5 next bytes.
+          offset += DexRegisterMap::SingleLargeEntrySize();
+        }
       }
     }
     size_t size = offset - origin;