[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/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;