Uleb128 compression of vmap and mapping table.

Bug 9437697.

Change-Id: I30bcb97d12cd8b46d3b2cdcbdd358f08fbb9947a
(cherry picked from commit 1809a72a66d245ae598582d658b93a24ac3bf01e)
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index c9780fa..5f6f3d5 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -17,6 +17,7 @@
 #include "dex/compiler_internals.h"
 #include "dex_file-inl.h"
 #include "gc_map.h"
+#include "mapping_table.h"
 #include "mir_to_lir-inl.h"
 #include "verifier/dex_gc_map.h"
 #include "verifier/method_verifier.h"
@@ -515,15 +516,35 @@
     }
   }
   if (kIsDebugBuild) {
-    DCHECK(VerifyCatchEntries());
+    CHECK(VerifyCatchEntries());
   }
-  combined_mapping_table_.push_back(pc2dex_mapping_table_.size() +
-                                        dex2pc_mapping_table_.size());
-  combined_mapping_table_.push_back(pc2dex_mapping_table_.size());
-  combined_mapping_table_.insert(combined_mapping_table_.end(), pc2dex_mapping_table_.begin(),
-                                 pc2dex_mapping_table_.end());
-  combined_mapping_table_.insert(combined_mapping_table_.end(), dex2pc_mapping_table_.begin(),
-                                 dex2pc_mapping_table_.end());
+  CHECK_EQ(pc2dex_mapping_table_.size() & 1, 0U);
+  CHECK_EQ(dex2pc_mapping_table_.size() & 1, 0U);
+  uint32_t total_entries = (pc2dex_mapping_table_.size() + dex2pc_mapping_table_.size()) / 2;
+  uint32_t pc2dex_entries = pc2dex_mapping_table_.size() / 2;
+  encoded_mapping_table_.PushBack(total_entries);
+  encoded_mapping_table_.PushBack(pc2dex_entries);
+  encoded_mapping_table_.InsertBack(pc2dex_mapping_table_.begin(), pc2dex_mapping_table_.end());
+  encoded_mapping_table_.InsertBack(dex2pc_mapping_table_.begin(), dex2pc_mapping_table_.end());
+  if (kIsDebugBuild) {
+    // Verify the encoded table holds the expected data.
+    MappingTable table(&encoded_mapping_table_.GetData()[0]);
+    CHECK_EQ(table.TotalSize(), total_entries);
+    CHECK_EQ(table.PcToDexSize(), pc2dex_entries);
+    CHECK_EQ(table.DexToPcSize(), dex2pc_mapping_table_.size() / 2);
+    MappingTable::PcToDexIterator it = table.PcToDexBegin();
+    for (uint32_t i = 0; i < pc2dex_mapping_table_.size(); ++i, ++it) {
+      CHECK_EQ(pc2dex_mapping_table_.at(i), it.NativePcOffset());
+      ++i;
+      CHECK_EQ(pc2dex_mapping_table_.at(i), it.DexPc());
+    }
+    MappingTable::DexToPcIterator it2 = table.DexToPcBegin();
+    for (uint32_t i = 0; i < dex2pc_mapping_table_.size(); ++i, ++it2) {
+      CHECK_EQ(dex2pc_mapping_table_.at(i), it2.NativePcOffset());
+      ++i;
+      CHECK_EQ(dex2pc_mapping_table_.at(i), it2.DexPc());
+    }
+  }
 }
 
 class NativePcToReferenceMapBuilder {
@@ -980,28 +1001,35 @@
 
 CompiledMethod* Mir2Lir::GetCompiledMethod() {
   // Combine vmap tables - core regs, then fp regs - into vmap_table
-  std::vector<uint16_t> 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
-    vmap_table.push_back(~(-1 << VREG_NUM_WIDTH) & core_vmap_table_[i]);
+    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
   if (frame_size_ > 0) {
-    vmap_table.push_back(INVALID_VREG);
+    raw_vmap_table.push_back(INVALID_VREG);
   } 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++) {
-    vmap_table.push_back(fp_vmap_table_[i]);
+    raw_vmap_table.push_back(fp_vmap_table_[i]);
+  }
+  UnsignedLeb128EncodingVector vmap_encoder;
+  // Prefix the encoded data with its size.
+  vmap_encoder.PushBack(raw_vmap_table.size());
+  typedef std::vector<uint16_t>::const_iterator It;
+  for (It cur = raw_vmap_table.begin(), end = raw_vmap_table.end(); cur != end; ++cur) {
+    vmap_encoder.PushBack(*cur);
   }
   CompiledMethod* result =
       new CompiledMethod(cu_->instruction_set, code_buffer_,
                          frame_size_, core_spill_mask_, fp_spill_mask_,
-                         combined_mapping_table_, vmap_table, native_gc_map_);
+                         encoded_mapping_table_.GetData(), vmap_encoder.GetData(), native_gc_map_);
   return result;
 }
 
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 2794bf5..517fc66 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -25,6 +25,7 @@
 #include "dex/growable_array.h"
 #include "dex/arena_allocator.h"
 #include "driver/compiler_driver.h"
+#include "leb128_encoder.h"
 #include "safe_map.h"
 
 namespace art {
@@ -760,7 +761,8 @@
      */
     int live_sreg_;
     CodeBuffer code_buffer_;
-    std::vector<uint32_t> combined_mapping_table_;
+    // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
+    UnsignedLeb128EncodingVector encoded_mapping_table_;
     std::vector<uint32_t> core_vmap_table_;
     std::vector<uint32_t> fp_vmap_table_;
     std::vector<uint8_t> native_gc_map_;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 550d642..3432c8c 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -547,11 +547,11 @@
         // Normal (non-abstract non-native) methods have various tables to relocate.
         uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
         const byte* mapping_table = GetOatAddress(mapping_table_off);
-        copy->SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table));
+        copy->SetMappingTable(mapping_table);
 
         uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
         const byte* vmap_table = GetOatAddress(vmap_table_offset);
-        copy->SetVmapTable(reinterpret_cast<const uint16_t*>(vmap_table));
+        copy->SetVmapTable(vmap_table);
 
         uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
         const byte* native_gc_map = GetOatAddress(native_gc_map_offset);
diff --git a/compiler/leb128_encoder.h b/compiler/leb128_encoder.h
new file mode 100644
index 0000000..e9a1c32
--- /dev/null
+++ b/compiler/leb128_encoder.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_LEB128_ENCODER_H_
+#define ART_COMPILER_LEB128_ENCODER_H_
+
+#include "base/macros.h"
+
+namespace art {
+
+// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
+class UnsignedLeb128EncodingVector {
+ public:
+  UnsignedLeb128EncodingVector() {
+  }
+
+  void PushBack(uint32_t value) {
+    bool done = false;
+    do {
+      uint8_t out = value & 0x7f;
+      if (out != value) {
+        data_.push_back(out | 0x80);
+        value >>= 7;
+      } else {
+        data_.push_back(out);
+        done = true;
+      }
+    } while (!done);
+  }
+
+  template<typename It>
+  void InsertBack(It cur, It end) {
+    for (; cur != end; ++cur) {
+      PushBack(*cur);
+    }
+  }
+
+  const std::vector<uint8_t>& GetData() const {
+    return data_;
+  }
+
+ private:
+  std::vector<uint8_t> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnsignedLeb128EncodingVector);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LEB128_ENCODER_H_
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 21c5317..ce88cf6 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -322,12 +322,12 @@
     core_spill_mask = compiled_method->GetCoreSpillMask();
     fp_spill_mask = compiled_method->GetFpSpillMask();
 
-    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
     mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
 
     // Deduplicate mapping tables
-    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
         mapping_table_offsets_.find(&mapping_table);
     if (mapping_iter != mapping_table_offsets_.end()) {
       mapping_table_offset = mapping_iter->second;
@@ -337,12 +337,12 @@
       oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
     }
 
-    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
     vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
 
     // Deduplicate vmap tables
-    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
         vmap_table_offsets_.find(&vmap_table);
     if (vmap_iter != vmap_table_offsets_.end()) {
       vmap_table_offset = vmap_iter->second;
@@ -717,11 +717,11 @@
     DCHECK_OFFSET();
 #endif
 
-    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
 
     // Deduplicate mapping tables
-    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
         mapping_table_offsets_.find(&mapping_table);
     if (mapping_iter != mapping_table_offsets_.end() &&
         relative_offset != method_offsets.mapping_table_offset_) {
@@ -741,11 +741,11 @@
     }
     DCHECK_OFFSET();
 
-    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
 
     // Deduplicate vmap tables
-    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
         vmap_table_offsets_.find(&vmap_table);
     if (vmap_iter != vmap_table_offsets_.end() &&
         relative_offset != method_offsets.vmap_table_offset_) {
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index e6cc0bc..f7801f5 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -226,8 +226,8 @@
 
   // code mappings for deduplication
   SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > code_offsets_;
-  SafeMap<const std::vector<uint16_t>*, uint32_t, MapCompare<std::vector<uint16_t> > > vmap_table_offsets_;
-  SafeMap<const std::vector<uint32_t>*, uint32_t, MapCompare<std::vector<uint32_t> > > mapping_table_offsets_;
+  SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > vmap_table_offsets_;
+  SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > mapping_table_offsets_;
   SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > gc_map_offsets_;
 
   DISALLOW_COPY_AND_ASSIGN(OatWriter);