Encode VmapTable entries offset by 2 to reduce size.

We're using special values 0xffff and 0xfffe for an
fp register marker and for method pointer, respectively.
These values were being encoded as 3 bytes each and
this changes their encoding to 1 byte.

Bug: 9437697
Change-Id: Ic1720e898b131a5d3f6ca87d8e1ecdf76fb4160a
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index c5dccda..3185449 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -25,6 +25,7 @@
 #include "dex/verified_method.h"
 #include "verifier/dex_gc_map.h"
 #include "verifier/method_verifier.h"
+#include "vmap_table.h"
 
 namespace art {
 
@@ -1042,30 +1043,32 @@
 }
 
 CompiledMethod* Mir2Lir::GetCompiledMethod() {
-  // Combine vmap tables - core regs, then fp regs - into vmap_table
-  std::vector<uint16_t> raw_vmap_table;
-  // Core regs may have been inserted out of order - sort first
-  std::sort(core_vmap_table_.begin(), core_vmap_table_.end());
-  for (size_t i = 0 ; i < core_vmap_table_.size(); ++i) {
-    // Copy, stripping out the phys register sort key
-    raw_vmap_table.push_back(~(-1 << VREG_NUM_WIDTH) & core_vmap_table_[i]);
-  }
-  // If we have a frame, push a marker to take place of lr
+  // Combine vmap tables - core regs, then fp regs - into vmap_table.
+  Leb128EncodingVector vmap_encoder;
   if (frame_size_ > 0) {
-    raw_vmap_table.push_back(INVALID_VREG);
+    // Prefix the encoded data with its size.
+    size_t size = core_vmap_table_.size() + 1 /* marker */ + fp_vmap_table_.size();
+    vmap_encoder.Reserve(size + 1u);  // All values are likely to be one byte in ULEB128 (<128).
+    vmap_encoder.PushBackUnsigned(size);
+    // Core regs may have been inserted out of order - sort first.
+    std::sort(core_vmap_table_.begin(), core_vmap_table_.end());
+    for (size_t i = 0 ; i < core_vmap_table_.size(); ++i) {
+      // Copy, stripping out the phys register sort key.
+      vmap_encoder.PushBackUnsigned(
+          ~(-1 << VREG_NUM_WIDTH) & (core_vmap_table_[i] + VmapTable::kEntryAdjustment));
+    }
+    // Push a marker to take place of lr.
+    vmap_encoder.PushBackUnsigned(VmapTable::kAdjustedFpMarker);
+    // fp regs already sorted.
+    for (uint32_t i = 0; i < fp_vmap_table_.size(); i++) {
+      vmap_encoder.PushBackUnsigned(fp_vmap_table_[i] + VmapTable::kEntryAdjustment);
+    }
   } else {
     DCHECK_EQ(__builtin_popcount(core_spill_mask_), 0);
     DCHECK_EQ(__builtin_popcount(fp_spill_mask_), 0);
-  }
-  // Combine vmap tables - core regs, then fp regs. fp regs already sorted
-  for (uint32_t i = 0; i < fp_vmap_table_.size(); i++) {
-    raw_vmap_table.push_back(fp_vmap_table_[i]);
-  }
-  Leb128EncodingVector vmap_encoder;
-  // Prefix the encoded data with its size.
-  vmap_encoder.PushBackUnsigned(raw_vmap_table.size());
-  for (uint16_t cur : raw_vmap_table) {
-    vmap_encoder.PushBackUnsigned(cur);
+    DCHECK_EQ(core_vmap_table_.size(), 0u);
+    DCHECK_EQ(fp_vmap_table_.size(), 0u);
+    vmap_encoder.PushBackUnsigned(0u);  // Size is 0.
   }
   CompiledMethod* result =
       new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index c7f537a..910a817 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -28,6 +28,7 @@
 #include "sirt_ref.h"
 #include "thread.h"
 #include "UniquePtr.h"
+#include "vmap_table.h"
 
 namespace art {
 
@@ -66,7 +67,7 @@
     fake_mapping_data_.PushBackUnsigned(3 - 0);  // offset 3
     fake_mapping_data_.PushBackSigned(3 - 0);    // maps to dex offset 3
 
-    fake_vmap_table_data_.PushBackUnsigned(0);
+    fake_vmap_table_data_.PushBackUnsigned(0 + VmapTable::kEntryAdjustment);
 
     fake_gc_map_.push_back(0);  // 0 bytes to encode references and native pc offsets.
     fake_gc_map_.push_back(0);
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 81d4540..945cd77 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '1', '4', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '5', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
diff --git a/runtime/vmap_table.h b/runtime/vmap_table.h
index abc50b9..2fbaebe 100644
--- a/runtime/vmap_table.h
+++ b/runtime/vmap_table.h
@@ -25,6 +25,10 @@
 
 class VmapTable {
  public:
+  // For efficient encoding of special values, entries are adjusted by 2.
+  static constexpr uint16_t kEntryAdjustment = 2u;
+  static constexpr uint16_t kAdjustedFpMarker = static_cast<uint16_t>(0xffffu + kEntryAdjustment);
+
   explicit VmapTable(const uint8_t* table) : table_(table) {
   }
 
@@ -33,11 +37,11 @@
     const uint8_t* table = table_;
     size_t size = DecodeUnsignedLeb128(&table);
     CHECK_LT(n, size);
-    uint16_t entry = DecodeUnsignedLeb128(&table);
+    uint16_t adjusted_entry = DecodeUnsignedLeb128(&table);
     for (size_t i = 0; i < n; ++i) {
-      entry = DecodeUnsignedLeb128(&table);
+      adjusted_entry = DecodeUnsignedLeb128(&table);
     }
-    return entry;
+    return adjusted_entry - kEntryAdjustment;
   }
 
   size_t Size() const {
@@ -58,16 +62,17 @@
     bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
     bool in_floats = false;
     const uint8_t* table = table_;
+    uint16_t adjusted_vreg = vreg + kEntryAdjustment;
     size_t end = DecodeUnsignedLeb128(&table);
     for (size_t i = 0; i < end; ++i) {
       // Stop if we find what we are are looking for.
-      uint16_t entry = DecodeUnsignedLeb128(&table);
-      if ((entry == vreg) && (in_floats == is_float)) {
+      uint16_t adjusted_entry = DecodeUnsignedLeb128(&table);
+      if ((adjusted_entry == adjusted_vreg) && (in_floats == is_float)) {
         *vmap_offset = i;
         return true;
       }
       // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers.
-      if (entry == 0xffff) {
+      if (adjusted_entry == kAdjustedFpMarker) {
         in_floats = true;
       }
     }
@@ -89,7 +94,7 @@
     if (UNLIKELY(is_float)) {
       const uint8_t* table = table_;
       DecodeUnsignedLeb128(&table);  // Skip size.
-      while (DecodeUnsignedLeb128(&table) != 0xffff) {
+      while (DecodeUnsignedLeb128(&table) != kAdjustedFpMarker) {
         matches++;
       }
       matches++;