Reduce memory used by CompiledMethods.

Use LengthPrefixedArray<>s instead of SwapVector<>s to store
CompiledMethod data and get rid of the unnecessary members
of CompiledMethod to reduce dex2oat memory usage. Refactor
the deduplication from CompilerDriver to a new class.

Use HashSet<> instead of std::set<> for the DedupeSet<> to
further decrease the memory usage and improve performance.

This reduces the dex2oat memory usage when compiling boot
image on Nexus 5 (with Optimizing, -j1) by ~6.75MiB (5%).
This also reduces the compile time by ~2.2% (~1.6% dex2oat
time; with Optimizing, without -j).

Change-Id: I974f1f5e58350de2bf487a2bca3907fa05fb80ea
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 6295e15..fdfd94c 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -230,6 +230,7 @@
   runtime/jni_internal_test.cc \
   runtime/proxy_test.cc \
   runtime/reflection_test.cc \
+  compiler/compiled_method_test.cc \
   compiler/dex/gvn_dead_code_elimination_test.cc \
   compiler/dex/global_value_numbering_test.cc \
   compiler/dex/local_value_numbering_test.cc \
@@ -237,6 +238,7 @@
   compiler/dex/mir_optimization_test.cc \
   compiler/dex/type_inference_test.cc \
   compiler/dwarf/dwarf_test.cc \
+  compiler/driver/compiled_method_storage_test.cc \
   compiler/driver/compiler_driver_test.cc \
   compiler/elf_writer_test.cc \
   compiler/image_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 17f9d12..4ae1403 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -54,6 +54,7 @@
 	dex/verification_results.cc \
 	dex/vreg_analysis.cc \
 	dex/quick_compiler_callbacks.cc \
+	driver/compiled_method_storage.cc \
 	driver/compiler_driver.cc \
 	driver/compiler_options.cc \
 	driver/dex_compilation_unit.cc \
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index 5e345db..6fd4575 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -51,7 +51,7 @@
     dwarf::WriteDebugFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
                               initial_opcodes, kCFIFormat, &debug_frame_data_);
     std::vector<uintptr_t> debug_frame_patches;
-    dwarf::WriteDebugFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
+    dwarf::WriteDebugFrameFDE(is64bit, 0, 0, actual_asm.size(), ArrayRef<const uint8_t>(actual_cfi),
                               kCFIFormat, &debug_frame_data_, &debug_frame_patches);
     ReformatCfi(Objdump(false, "-W"), &lines);
     // Pretty-print assembly.
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 58a2f96..151437b 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -54,22 +54,22 @@
                                                             method->GetDexMethodIndex()));
   }
   if (compiled_method != nullptr) {
-    const SwapVector<uint8_t>* code = compiled_method->GetQuickCode();
-    uint32_t code_size = code->size();
+    ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
+    uint32_t code_size = code.size();
     CHECK_NE(0u, code_size);
-    const SwapVector<uint8_t>* vmap_table = compiled_method->GetVmapTable();
-    uint32_t vmap_table_offset = vmap_table->empty() ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table->size();
-    const SwapVector<uint8_t>* mapping_table = compiled_method->GetMappingTable();
-    bool mapping_table_used = mapping_table != nullptr && !mapping_table->empty();
-    size_t mapping_table_size = mapping_table_used ? mapping_table->size() : 0U;
+    ArrayRef<const uint8_t> vmap_table = compiled_method->GetVmapTable();
+    uint32_t vmap_table_offset = vmap_table.empty() ? 0u
+        : sizeof(OatQuickMethodHeader) + vmap_table.size();
+    ArrayRef<const uint8_t> mapping_table = compiled_method->GetMappingTable();
+    bool mapping_table_used = !mapping_table.empty();
+    size_t mapping_table_size = mapping_table.size();
     uint32_t mapping_table_offset = !mapping_table_used ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size;
-    const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
-    bool gc_map_used = gc_map != nullptr && !gc_map->empty();
-    size_t gc_map_size = gc_map_used ? gc_map->size() : 0U;
+        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size;
+    ArrayRef<const uint8_t> gc_map = compiled_method->GetGcMap();
+    bool gc_map_used = !gc_map.empty();
+    size_t gc_map_size = gc_map.size();
     uint32_t gc_map_offset = !gc_map_used ? 0u
-        : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size + gc_map_size;
+        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size + gc_map_size;
     OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
                                        compiled_method->GetFrameSizeInBytes(),
                                        compiled_method->GetCoreSpillMask(),
@@ -77,25 +77,25 @@
 
     header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
     std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
-    size_t size = sizeof(method_header) + code_size + vmap_table->size() + mapping_table_size +
+    size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table_size +
         gc_map_size;
     size_t code_offset = compiled_method->AlignCode(size - code_size);
     size_t padding = code_offset - (size - code_size);
     chunk->reserve(padding + size);
     chunk->resize(sizeof(method_header));
     memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
-    chunk->insert(chunk->begin(), vmap_table->begin(), vmap_table->end());
+    chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
     if (mapping_table_used) {
-      chunk->insert(chunk->begin(), mapping_table->begin(), mapping_table->end());
+      chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
     }
     if (gc_map_used) {
-      chunk->insert(chunk->begin(), gc_map->begin(), gc_map->end());
+      chunk->insert(chunk->begin(), gc_map.begin(), gc_map.end());
     }
     chunk->insert(chunk->begin(), padding, 0);
-    chunk->insert(chunk->end(), code->begin(), code->end());
+    chunk->insert(chunk->end(), code.begin(), code.end());
     CHECK_EQ(padding + size, chunk->size());
     const void* code_ptr = &(*chunk)[code_offset];
-    MakeExecutable(code_ptr, code->size());
+    MakeExecutable(code_ptr, code.size());
     const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                           compiled_method->GetInstructionSet());
     LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 74ef35e..9551d22 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -15,27 +15,22 @@
  */
 
 #include "compiled_method.h"
+
+#include "driver/compiled_method_storage.h"
 #include "driver/compiler_driver.h"
+#include "utils/swap_space.h"
 
 namespace art {
 
 CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-                           const ArrayRef<const uint8_t>& quick_code, bool owns_code_array)
-    : compiler_driver_(compiler_driver), instruction_set_(instruction_set),
-      owns_code_array_(owns_code_array), quick_code_(nullptr) {
-  if (owns_code_array_) {
-    // If we are supposed to own the code, don't deduplicate it.
-    quick_code_ = new SwapVector<uint8_t>(quick_code.begin(), quick_code.end(),
-                                          compiler_driver_->GetSwapSpaceAllocator());
-  } else {
-    quick_code_ = compiler_driver_->DeduplicateCode(quick_code);
-  }
+                           const ArrayRef<const uint8_t>& quick_code)
+    : compiler_driver_(compiler_driver),
+      instruction_set_(instruction_set),
+      quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)) {
 }
 
 CompiledCode::~CompiledCode() {
-  if (owns_code_array_) {
-    delete quick_code_;
-  }
+  compiler_driver_->GetCompiledMethodStorage()->ReleaseCode(quick_code_);
 }
 
 bool CompiledCode::operator==(const CompiledCode& rhs) const {
@@ -104,59 +99,28 @@
   }
 }
 
-const std::vector<uint32_t>& CompiledCode::GetOatdataOffsetsToCompliledCodeOffset() const {
-  CHECK_NE(0U, oatdata_offsets_to_compiled_code_offset_.size());
-  return oatdata_offsets_to_compiled_code_offset_;
-}
-
-void CompiledCode::AddOatdataOffsetToCompliledCodeOffset(uint32_t offset) {
-  oatdata_offsets_to_compiled_code_offset_.push_back(offset);
-}
-
 CompiledMethod::CompiledMethod(CompilerDriver* driver,
                                InstructionSet instruction_set,
                                const ArrayRef<const uint8_t>& quick_code,
                                const size_t frame_size_in_bytes,
                                const uint32_t core_spill_mask,
                                const uint32_t fp_spill_mask,
-                               DefaultSrcMap* src_mapping_table,
+                               const ArrayRef<const SrcMapElem>& src_mapping_table,
                                const ArrayRef<const uint8_t>& mapping_table,
                                const ArrayRef<const uint8_t>& vmap_table,
                                const ArrayRef<const uint8_t>& native_gc_map,
                                const ArrayRef<const uint8_t>& cfi_info,
                                const ArrayRef<const LinkerPatch>& patches)
-    : CompiledCode(driver, instruction_set, quick_code, !driver->DedupeEnabled()),
-      owns_arrays_(!driver->DedupeEnabled()),
+    : CompiledCode(driver, instruction_set, quick_code),
       frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask),
       fp_spill_mask_(fp_spill_mask),
-      patches_(patches.begin(), patches.end(), driver->GetSwapSpaceAllocator()) {
-  if (owns_arrays_) {
-    if (src_mapping_table == nullptr) {
-      src_mapping_table_ = new SwapSrcMap(driver->GetSwapSpaceAllocator());
-    } else {
-      src_mapping_table_ = new SwapSrcMap(src_mapping_table->begin(), src_mapping_table->end(),
-                                          driver->GetSwapSpaceAllocator());
-    }
-    mapping_table_ = mapping_table.empty() ?
-        nullptr : new SwapVector<uint8_t>(mapping_table.begin(), mapping_table.end(),
-                                          driver->GetSwapSpaceAllocator());
-    vmap_table_ = new SwapVector<uint8_t>(vmap_table.begin(), vmap_table.end(),
-                                          driver->GetSwapSpaceAllocator());
-    gc_map_ = native_gc_map.empty() ? nullptr :
-        new SwapVector<uint8_t>(native_gc_map.begin(), native_gc_map.end(),
-                                driver->GetSwapSpaceAllocator());
-    cfi_info_ = cfi_info.empty() ? nullptr :
-        new SwapVector<uint8_t>(cfi_info.begin(), cfi_info.end(), driver->GetSwapSpaceAllocator());
-  } else {
-    src_mapping_table_ = src_mapping_table == nullptr ?
-        driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) :
-        driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(*src_mapping_table));
-    mapping_table_ = mapping_table.empty() ?
-        nullptr : driver->DeduplicateMappingTable(mapping_table);
-    vmap_table_ = driver->DeduplicateVMapTable(vmap_table);
-    gc_map_ = native_gc_map.empty() ? nullptr : driver->DeduplicateGCMap(native_gc_map);
-    cfi_info_ = cfi_info.empty() ? nullptr : driver->DeduplicateCFIInfo(cfi_info);
-  }
+      src_mapping_table_(
+          driver->GetCompiledMethodStorage()->DeduplicateSrcMappingTable(src_mapping_table)),
+      mapping_table_(driver->GetCompiledMethodStorage()->DeduplicateMappingTable(mapping_table)),
+      vmap_table_(driver->GetCompiledMethodStorage()->DeduplicateVMapTable(vmap_table)),
+      gc_map_(driver->GetCompiledMethodStorage()->DeduplicateGCMap(native_gc_map)),
+      cfi_info_(driver->GetCompiledMethodStorage()->DeduplicateCFIInfo(cfi_info)),
+      patches_(driver->GetCompiledMethodStorage()->DeduplicateLinkerPatches(patches)) {
 }
 
 CompiledMethod* CompiledMethod::SwapAllocCompiledMethod(
@@ -166,13 +130,13 @@
     const size_t frame_size_in_bytes,
     const uint32_t core_spill_mask,
     const uint32_t fp_spill_mask,
-    DefaultSrcMap* src_mapping_table,
+    const ArrayRef<const SrcMapElem>& src_mapping_table,
     const ArrayRef<const uint8_t>& mapping_table,
     const ArrayRef<const uint8_t>& vmap_table,
     const ArrayRef<const uint8_t>& native_gc_map,
     const ArrayRef<const uint8_t>& cfi_info,
     const ArrayRef<const LinkerPatch>& patches) {
-  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
   CompiledMethod* ret = alloc.allocate(1);
   alloc.construct(ret, driver, instruction_set, quick_code, frame_size_in_bytes, core_spill_mask,
                   fp_spill_mask, src_mapping_table, mapping_table, vmap_table, native_gc_map,
@@ -180,22 +144,20 @@
   return ret;
 }
 
-
-
 void CompiledMethod::ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m) {
-  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
   alloc.destroy(m);
   alloc.deallocate(m, 1);
 }
 
 CompiledMethod::~CompiledMethod() {
-  if (owns_arrays_) {
-    delete src_mapping_table_;
-    delete mapping_table_;
-    delete vmap_table_;
-    delete gc_map_;
-    delete cfi_info_;
-  }
+  CompiledMethodStorage* storage = GetCompilerDriver()->GetCompiledMethodStorage();
+  storage->ReleaseLinkerPatches(patches_);
+  storage->ReleaseCFIInfo(cfi_info_);
+  storage->ReleaseGCMap(gc_map_);
+  storage->ReleaseVMapTable(vmap_table_);
+  storage->ReleaseMappingTable(mapping_table_);
+  storage->ReleaseSrcMappingTable(src_mapping_table_);
 }
 
 }  // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index a4d2387..15a4ba0 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -23,19 +23,20 @@
 
 #include "arch/instruction_set.h"
 #include "base/bit_utils.h"
+#include "length_prefixed_array.h"
 #include "method_reference.h"
 #include "utils/array_ref.h"
-#include "utils/swap_space.h"
 
 namespace art {
 
 class CompilerDriver;
+class CompiledMethodStorage;
 
 class CompiledCode {
  public:
   // For Quick to supply an code blob
   CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-               const ArrayRef<const uint8_t>& quick_code, bool owns_code_array);
+               const ArrayRef<const uint8_t>& quick_code);
 
   virtual ~CompiledCode();
 
@@ -43,8 +44,8 @@
     return instruction_set_;
   }
 
-  const SwapVector<uint8_t>* GetQuickCode() const {
-    return quick_code_;
+  ArrayRef<const uint8_t> GetQuickCode() const {
+    return GetArray(quick_code_);
   }
 
   bool operator==(const CompiledCode& rhs) const;
@@ -66,41 +67,46 @@
   static const void* CodePointer(const void* code_pointer,
                                  InstructionSet instruction_set);
 
-  const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const;
-  void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset);
+ protected:
+  template <typename T>
+  static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array) {
+    if (array == nullptr) {
+      return ArrayRef<const T>();
+    }
+    DCHECK_NE(array->size(), 0u);
+    return ArrayRef<const T>(&array->At(0), array->size());
+  }
+
+  CompilerDriver* GetCompilerDriver() {
+    return compiler_driver_;
+  }
 
  private:
   CompilerDriver* const compiler_driver_;
 
   const InstructionSet instruction_set_;
 
-  // If we own the code array (means that we free in destructor).
-  const bool owns_code_array_;
-
   // Used to store the PIC code for Quick.
-  SwapVector<uint8_t>* quick_code_;
-
-  // There are offsets from the oatdata symbol to where the offset to
-  // the compiled method will be found. These are computed by the
-  // OatWriter and then used by the ElfWriter to add relocations so
-  // that MCLinker can update the values to the location in the linked .so.
-  std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_;
+  const LengthPrefixedArray<uint8_t>* const quick_code_;
 };
 
 class SrcMapElem {
  public:
   uint32_t from_;
   int32_t to_;
-
-  // Lexicographical compare.
-  bool operator<(const SrcMapElem& other) const {
-    if (from_ != other.from_) {
-      return from_ < other.from_;
-    }
-    return to_ < other.to_;
-  }
 };
 
+inline bool operator<(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  if (lhs.from_ != rhs.from_) {
+    return lhs.from_ < rhs.from_;
+  }
+  return lhs.to_ < rhs.to_;
+}
+
+inline bool operator==(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  return lhs.from_ == rhs.from_ && lhs.to_ == rhs.to_;
+}
+
 template <class Allocator>
 class SrcMap FINAL : public std::vector<SrcMapElem, Allocator> {
  public:
@@ -151,7 +157,6 @@
 };
 
 using DefaultSrcMap = SrcMap<std::allocator<SrcMapElem>>;
-using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>;
 
 
 enum LinkerPatchType {
@@ -273,6 +278,9 @@
     uint32_t method_idx_;       // Method index for Call/Method patches.
     uint32_t type_idx_;         // Type index for Type patches.
     uint32_t element_offset_;   // Element offset in the dex cache arrays.
+    static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
+    static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
+    static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators");
   };
   union {
     uint32_t cmp2_;             // Used for relational operators.
@@ -313,7 +321,7 @@
                  const size_t frame_size_in_bytes,
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask,
-                 DefaultSrcMap* src_mapping_table,
+                 const ArrayRef<const SrcMapElem>& src_mapping_table,
                  const ArrayRef<const uint8_t>& mapping_table,
                  const ArrayRef<const uint8_t>& vmap_table,
                  const ArrayRef<const uint8_t>& native_gc_map,
@@ -329,7 +337,7 @@
       const size_t frame_size_in_bytes,
       const uint32_t core_spill_mask,
       const uint32_t fp_spill_mask,
-      DefaultSrcMap* src_mapping_table,
+      const ArrayRef<const SrcMapElem>& src_mapping_table,
       const ArrayRef<const uint8_t>& mapping_table,
       const ArrayRef<const uint8_t>& vmap_table,
       const ArrayRef<const uint8_t>& native_gc_map,
@@ -350,35 +358,31 @@
     return fp_spill_mask_;
   }
 
-  const SwapSrcMap& GetSrcMappingTable() const {
-    DCHECK(src_mapping_table_ != nullptr);
-    return *src_mapping_table_;
+  ArrayRef<const SrcMapElem> GetSrcMappingTable() const {
+    return GetArray(src_mapping_table_);
   }
 
-  SwapVector<uint8_t> const* GetMappingTable() const {
-    return mapping_table_;
+  ArrayRef<const uint8_t> GetMappingTable() const {
+    return GetArray(mapping_table_);
   }
 
-  const SwapVector<uint8_t>* GetVmapTable() const {
-    DCHECK(vmap_table_ != nullptr);
-    return vmap_table_;
+  ArrayRef<const uint8_t> GetVmapTable() const {
+    return GetArray(vmap_table_);
   }
 
-  SwapVector<uint8_t> const* GetGcMap() const {
-    return gc_map_;
+  ArrayRef<const uint8_t> GetGcMap() const {
+    return GetArray(gc_map_);
   }
 
-  const SwapVector<uint8_t>* GetCFIInfo() const {
-    return cfi_info_;
+  ArrayRef<const uint8_t> GetCFIInfo() const {
+    return GetArray(cfi_info_);
   }
 
   ArrayRef<const LinkerPatch> GetPatches() const {
-    return ArrayRef<const LinkerPatch>(patches_);
+    return GetArray(patches_);
   }
 
  private:
-  // Whether or not the arrays are owned by the compiled method or dedupe sets.
-  const bool owns_arrays_;
   // For quick code, the size of the activation used by the code.
   const size_t frame_size_in_bytes_;
   // For quick code, a bit mask describing spilled GPR callee-save registers.
@@ -386,19 +390,19 @@
   // For quick code, a bit mask describing spilled FPR callee-save registers.
   const uint32_t fp_spill_mask_;
   // For quick code, a set of pairs (PC, DEX) mapping from native PC offset to DEX offset.
-  SwapSrcMap* src_mapping_table_;
+  const LengthPrefixedArray<SrcMapElem>* const src_mapping_table_;
   // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to
   // native PC offset. Size prefixed.
-  SwapVector<uint8_t>* mapping_table_;
+  const LengthPrefixedArray<uint8_t>* const mapping_table_;
   // For quick code, a uleb128 encoded map from GPR/FPR register to dex register. Size prefixed.
-  SwapVector<uint8_t>* vmap_table_;
+  const LengthPrefixedArray<uint8_t>* const vmap_table_;
   // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
   // are live.
-  SwapVector<uint8_t>* gc_map_;
+  const LengthPrefixedArray<uint8_t>* const gc_map_;
   // For quick code, a FDE entry for the debug_frame section.
-  SwapVector<uint8_t>* cfi_info_;
+  const LengthPrefixedArray<uint8_t>* const cfi_info_;
   // For quick code, linker patches needed by the method.
-  const SwapVector<LinkerPatch> patches_;
+  const LengthPrefixedArray<LinkerPatch>* const patches_;
 };
 
 }  // namespace art
diff --git a/compiler/compiled_method_test.cc b/compiler/compiled_method_test.cc
new file mode 100644
index 0000000..99ee875
--- /dev/null
+++ b/compiler/compiled_method_test.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "compiled_method.h"
+
+namespace art {
+
+TEST(CompiledMethod, SrcMapElemOperators) {
+  SrcMapElem elems[] = {
+      { 1u, -1 },
+      { 1u, 0 },
+      { 1u, 1 },
+      { 2u, -1 },
+      { 2u, 0 },    // Index 4.
+      { 2u, 1 },
+      { 2u, 0u },   // Index 6: Arbitrarily add identical SrcMapElem with index 4.
+  };
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) == (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] == elems[j]) << i << " " << j;
+    }
+  }
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) < (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] < elems[j]) << i << " " << j;
+    }
+  }
+}
+
+TEST(CompiledMethod, LinkerPatchOperators) {
+  const DexFile* dex_file1 = reinterpret_cast<const DexFile*>(1);
+  const DexFile* dex_file2 = reinterpret_cast<const DexFile*>(2);
+  LinkerPatch patches[] = {
+      LinkerPatch::MethodPatch(16u, dex_file1, 1000u),
+      LinkerPatch::MethodPatch(16u, dex_file1, 1001u),
+      LinkerPatch::MethodPatch(16u, dex_file2, 1000u),
+      LinkerPatch::MethodPatch(16u, dex_file2, 1001u),  // Index 3.
+      LinkerPatch::CodePatch(16u, dex_file1, 1000u),
+      LinkerPatch::CodePatch(16u, dex_file1, 1001u),
+      LinkerPatch::CodePatch(16u, dex_file2, 1000u),
+      LinkerPatch::CodePatch(16u, dex_file2, 1001u),
+      LinkerPatch::RelativeCodePatch(16u, dex_file1, 1000u),
+      LinkerPatch::RelativeCodePatch(16u, dex_file1, 1001u),
+      LinkerPatch::RelativeCodePatch(16u, dex_file2, 1000u),
+      LinkerPatch::RelativeCodePatch(16u, dex_file2, 1001u),
+      LinkerPatch::TypePatch(16u, dex_file1, 1000u),
+      LinkerPatch::TypePatch(16u, dex_file1, 1001u),
+      LinkerPatch::TypePatch(16u, dex_file2, 1000u),
+      LinkerPatch::TypePatch(16u, dex_file2, 1001u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2001u),
+      LinkerPatch::MethodPatch(32u, dex_file1, 1000u),
+      LinkerPatch::MethodPatch(32u, dex_file1, 1001u),
+      LinkerPatch::MethodPatch(32u, dex_file2, 1000u),
+      LinkerPatch::MethodPatch(32u, dex_file2, 1001u),
+      LinkerPatch::CodePatch(32u, dex_file1, 1000u),
+      LinkerPatch::CodePatch(32u, dex_file1, 1001u),
+      LinkerPatch::CodePatch(32u, dex_file2, 1000u),
+      LinkerPatch::CodePatch(32u, dex_file2, 1001u),
+      LinkerPatch::RelativeCodePatch(32u, dex_file1, 1000u),
+      LinkerPatch::RelativeCodePatch(32u, dex_file1, 1001u),
+      LinkerPatch::RelativeCodePatch(32u, dex_file2, 1000u),
+      LinkerPatch::RelativeCodePatch(32u, dex_file2, 1001u),
+      LinkerPatch::TypePatch(32u, dex_file1, 1000u),
+      LinkerPatch::TypePatch(32u, dex_file1, 1001u),
+      LinkerPatch::TypePatch(32u, dex_file2, 1000u),
+      LinkerPatch::TypePatch(32u, dex_file2, 1001u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2000u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2001u),
+      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2001u),
+      LinkerPatch::MethodPatch(16u, dex_file2, 1001u),  // identical with patch as index 3.
+  };
+  constexpr size_t last_index = arraysize(patches) - 1u;
+
+  for (size_t i = 0; i != arraysize(patches); ++i) {
+    for (size_t j = 0; j != arraysize(patches); ++j) {
+      bool expected = (i != last_index ? i : 3u) == (j != last_index ? j : 3u);
+      EXPECT_EQ(expected, patches[i] == patches[j]) << i << " " << j;
+    }
+  }
+
+  for (size_t i = 0; i != arraysize(patches); ++i) {
+    for (size_t j = 0; j != arraysize(patches); ++j) {
+      bool expected = (i != last_index ? i : 3u) < (j != last_index ? j : 3u);
+      EXPECT_EQ(expected, patches[i] < patches[j]) << i << " " << j;
+    }
+  }
+}
+
+}  // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index ff7ddc1..4836041 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -356,7 +356,7 @@
         0,
         0,
         0,
-        nullptr,                                     // src_mapping_table
+        ArrayRef<const SrcMapElem>(),                // src_mapping_table
         ArrayRef<const uint8_t>(),                   // mapping_table
         ArrayRef<const uint8_t>(builder.GetData()),  // vmap_table
         ArrayRef<const uint8_t>(),                   // gc_map
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index cde99b3..d68835a 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -22,6 +22,7 @@
 #endif
 
 #include "base/bit_vector-inl.h"
+#include "base/stringprintf.h"
 #include "dex/mir_graph.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
@@ -1165,7 +1166,7 @@
       cu_->compiler_driver, cu_->instruction_set,
       ArrayRef<const uint8_t>(code_buffer_),
       frame_size_, core_spill_mask_, fp_spill_mask_,
-      &src_mapping_table_,
+      ArrayRef<const SrcMapElem>(src_mapping_table_),
       ArrayRef<const uint8_t>(encoded_mapping_table_),
       ArrayRef<const uint8_t>(vmap_encoder.GetData()),
       ArrayRef<const uint8_t>(native_gc_map_),
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index d9d0434..dceb118 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -18,6 +18,7 @@
 
 #include "mir_to_lir-inl.h"
 
+#include "base/stringprintf.h"
 #include "dex/compiler_ir.h"
 #include "dex/dataflow_iterator-inl.h"
 #include "dex/mir_graph.h"
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
new file mode 100644
index 0000000..bc5c6ca
--- /dev/null
+++ b/compiler/driver/compiled_method_storage.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <algorithm>
+#include <ostream>
+
+#include "compiled_method_storage.h"
+
+#include "base/logging.h"
+#include "compiled_method.h"
+#include "thread-inl.h"
+#include "utils.h"
+#include "utils/dedupe_set-inl.h"
+#include "utils/swap_space.h"
+
+namespace art {
+
+namespace {  // anonymous namespace
+
+template <typename T>
+const LengthPrefixedArray<T>* CopyArray(SwapSpace* swap_space, const ArrayRef<const T>& array) {
+  DCHECK(!array.empty());
+  SwapAllocator<uint8_t> allocator(swap_space);
+  void* storage = allocator.allocate(LengthPrefixedArray<T>::ComputeSize(array.size()));
+  LengthPrefixedArray<T>* array_copy = new(storage) LengthPrefixedArray<T>(array.size());
+  std::copy(array.begin(), array.end(), array_copy->begin());
+  return array_copy;
+}
+
+template <typename T>
+void ReleaseArray(SwapSpace* swap_space, const LengthPrefixedArray<T>* array) {
+  SwapAllocator<uint8_t> allocator(swap_space);
+  size_t size = LengthPrefixedArray<T>::ComputeSize(array->size());
+  array->~LengthPrefixedArray<T>();
+  allocator.deallocate(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(array)), size);
+}
+
+}  // anonymous namespace
+
+template <typename T, typename DedupeSetType>
+inline const LengthPrefixedArray<T>* CompiledMethodStorage::AllocateOrDeduplicateArray(
+    const ArrayRef<const T>& data,
+    DedupeSetType* dedupe_set) {
+  if (data.empty()) {
+    return nullptr;
+  } else if (!DedupeEnabled()) {
+    return CopyArray(swap_space_.get(), data);
+  } else {
+    return dedupe_set->Add(Thread::Current(), data);
+  }
+}
+
+template <typename T>
+inline void CompiledMethodStorage::ReleaseArrayIfNotDeduplicated(
+    const LengthPrefixedArray<T>* array) {
+  if (array != nullptr && !DedupeEnabled()) {
+    ReleaseArray(swap_space_.get(), array);
+  }
+}
+
+template <typename ContentType>
+class CompiledMethodStorage::DedupeHashFunc {
+ private:
+  static constexpr bool kUseMurmur3Hash = true;
+
+ public:
+  size_t operator()(const ArrayRef<ContentType>& array) const {
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(array.data());
+    // TODO: More reasonable assertion.
+    // static_assert(IsPowerOfTwo(sizeof(ContentType)),
+    //    "ContentType is not power of two, don't know whether array layout is as assumed");
+    uint32_t len = sizeof(ContentType) * array.size();
+    if (kUseMurmur3Hash) {
+      static constexpr uint32_t c1 = 0xcc9e2d51;
+      static constexpr uint32_t c2 = 0x1b873593;
+      static constexpr uint32_t r1 = 15;
+      static constexpr uint32_t r2 = 13;
+      static constexpr uint32_t m = 5;
+      static constexpr uint32_t n = 0xe6546b64;
+
+      uint32_t hash = 0;
+
+      const int nblocks = len / 4;
+      typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+      const unaligned_uint32_t *blocks = reinterpret_cast<const uint32_t*>(data);
+      int i;
+      for (i = 0; i < nblocks; i++) {
+        uint32_t k = blocks[i];
+        k *= c1;
+        k = (k << r1) | (k >> (32 - r1));
+        k *= c2;
+
+        hash ^= k;
+        hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
+      }
+
+      const uint8_t *tail = reinterpret_cast<const uint8_t*>(data + nblocks * 4);
+      uint32_t k1 = 0;
+
+      switch (len & 3) {
+        case 3:
+          k1 ^= tail[2] << 16;
+          FALLTHROUGH_INTENDED;
+        case 2:
+          k1 ^= tail[1] << 8;
+          FALLTHROUGH_INTENDED;
+        case 1:
+          k1 ^= tail[0];
+
+          k1 *= c1;
+          k1 = (k1 << r1) | (k1 >> (32 - r1));
+          k1 *= c2;
+          hash ^= k1;
+      }
+
+      hash ^= len;
+      hash ^= (hash >> 16);
+      hash *= 0x85ebca6b;
+      hash ^= (hash >> 13);
+      hash *= 0xc2b2ae35;
+      hash ^= (hash >> 16);
+
+      return hash;
+    } else {
+      size_t hash = 0x811c9dc5;
+      for (uint32_t i = 0; i < len; ++i) {
+        hash = (hash * 16777619) ^ data[i];
+      }
+      hash += hash << 13;
+      hash ^= hash >> 7;
+      hash += hash << 3;
+      hash ^= hash >> 17;
+      hash += hash << 5;
+      return hash;
+    }
+  }
+};
+
+template <typename T>
+class CompiledMethodStorage::LengthPrefixedArrayAlloc {
+ public:
+  explicit LengthPrefixedArrayAlloc(SwapSpace* swap_space)
+      : swap_space_(swap_space) {
+  }
+
+  const LengthPrefixedArray<T>* Copy(const ArrayRef<const T>& array) {
+    return CopyArray(swap_space_, array);
+  }
+
+  void Destroy(const LengthPrefixedArray<T>* array) {
+    ReleaseArray(swap_space_, array);
+  }
+
+ private:
+  SwapSpace* const swap_space_;
+};
+
+CompiledMethodStorage::CompiledMethodStorage(int swap_fd)
+    : swap_space_(swap_fd == -1 ? nullptr : new SwapSpace(swap_fd, 10 * MB)),
+      dedupe_enabled_(true),
+      dedupe_code_("dedupe code", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
+      dedupe_src_mapping_table_("dedupe source mapping table",
+                                LengthPrefixedArrayAlloc<SrcMapElem>(swap_space_.get())),
+      dedupe_mapping_table_("dedupe mapping table",
+                            LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
+      dedupe_vmap_table_("dedupe vmap table",
+                         LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
+      dedupe_gc_map_("dedupe gc map", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
+      dedupe_cfi_info_("dedupe cfi info", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
+      dedupe_linker_patches_("dedupe cfi info",
+                             LengthPrefixedArrayAlloc<LinkerPatch>(swap_space_.get())) {
+}
+
+CompiledMethodStorage::~CompiledMethodStorage() {
+  // All done by member destructors.
+}
+
+void CompiledMethodStorage::DumpMemoryUsage(std::ostream& os, bool extended) const {
+  if (swap_space_.get() != nullptr) {
+    os << " swap=" << PrettySize(swap_space_->GetSize());
+  }
+  if (extended) {
+    Thread* self = Thread::Current();
+    os << "\nCode dedupe: " << dedupe_code_.DumpStats(self);
+    os << "\nMapping table dedupe: " << dedupe_mapping_table_.DumpStats(self);
+    os << "\nVmap table dedupe: " << dedupe_vmap_table_.DumpStats(self);
+    os << "\nGC map dedupe: " << dedupe_gc_map_.DumpStats(self);
+    os << "\nCFI info dedupe: " << dedupe_cfi_info_.DumpStats(self);
+  }
+}
+
+const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCode(
+    const ArrayRef<const uint8_t>& code) {
+  return AllocateOrDeduplicateArray(code, &dedupe_code_);
+}
+
+void CompiledMethodStorage::ReleaseCode(const LengthPrefixedArray<uint8_t>* code) {
+  ReleaseArrayIfNotDeduplicated(code);
+}
+
+const LengthPrefixedArray<SrcMapElem>* CompiledMethodStorage::DeduplicateSrcMappingTable(
+    const ArrayRef<const SrcMapElem>& src_map) {
+  return AllocateOrDeduplicateArray(src_map, &dedupe_src_mapping_table_);
+}
+
+void CompiledMethodStorage::ReleaseSrcMappingTable(const LengthPrefixedArray<SrcMapElem>* src_map) {
+  ReleaseArrayIfNotDeduplicated(src_map);
+}
+
+const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateMappingTable(
+    const ArrayRef<const uint8_t>& table) {
+  return AllocateOrDeduplicateArray(table, &dedupe_mapping_table_);
+}
+
+void CompiledMethodStorage::ReleaseMappingTable(const LengthPrefixedArray<uint8_t>* table) {
+  ReleaseArrayIfNotDeduplicated(table);
+}
+
+const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateVMapTable(
+    const ArrayRef<const uint8_t>& table) {
+  return AllocateOrDeduplicateArray(table, &dedupe_vmap_table_);
+}
+
+void CompiledMethodStorage::ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* table) {
+  ReleaseArrayIfNotDeduplicated(table);
+}
+
+const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateGCMap(
+    const ArrayRef<const uint8_t>& gc_map) {
+  return AllocateOrDeduplicateArray(gc_map, &dedupe_gc_map_);
+}
+
+void CompiledMethodStorage::ReleaseGCMap(const LengthPrefixedArray<uint8_t>* gc_map) {
+  ReleaseArrayIfNotDeduplicated(gc_map);
+}
+
+const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCFIInfo(
+    const ArrayRef<const uint8_t>& cfi_info) {
+  return AllocateOrDeduplicateArray(cfi_info, &dedupe_cfi_info_);
+}
+
+void CompiledMethodStorage::ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info) {
+  ReleaseArrayIfNotDeduplicated(cfi_info);
+}
+
+const LengthPrefixedArray<LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
+    const ArrayRef<const LinkerPatch>& linker_patches) {
+  return AllocateOrDeduplicateArray(linker_patches, &dedupe_linker_patches_);
+}
+
+void CompiledMethodStorage::ReleaseLinkerPatches(
+    const LengthPrefixedArray<LinkerPatch>* linker_patches) {
+  ReleaseArrayIfNotDeduplicated(linker_patches);
+}
+
+}  // namespace art
diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h
new file mode 100644
index 0000000..ef10b67
--- /dev/null
+++ b/compiler/driver/compiled_method_storage.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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_DRIVER_COMPILED_METHOD_STORAGE_H_
+#define ART_COMPILER_DRIVER_COMPILED_METHOD_STORAGE_H_
+
+#include <iosfwd>
+#include <memory>
+
+#include "base/macros.h"
+#include "length_prefixed_array.h"
+#include "utils/array_ref.h"
+#include "utils/dedupe_set.h"
+#include "utils/swap_space.h"
+
+namespace art {
+
+class LinkerPatch;
+class SrcMapElem;
+
+class CompiledMethodStorage {
+ public:
+  explicit CompiledMethodStorage(int swap_fd);
+  ~CompiledMethodStorage();
+
+  void DumpMemoryUsage(std::ostream& os, bool extended) const;
+
+  void SetDedupeEnabled(bool dedupe_enabled) {
+    dedupe_enabled_ = dedupe_enabled;
+  }
+  bool DedupeEnabled() const {
+    return dedupe_enabled_;
+  }
+
+  SwapAllocator<void> GetSwapSpaceAllocator() {
+    return SwapAllocator<void>(swap_space_.get());
+  }
+
+  const LengthPrefixedArray<uint8_t>* DeduplicateCode(const ArrayRef<const uint8_t>& code);
+  void ReleaseCode(const LengthPrefixedArray<uint8_t>* code);
+
+  const LengthPrefixedArray<SrcMapElem>* DeduplicateSrcMappingTable(
+      const ArrayRef<const SrcMapElem>& src_map);
+  void ReleaseSrcMappingTable(const LengthPrefixedArray<SrcMapElem>* src_map);
+
+  const LengthPrefixedArray<uint8_t>* DeduplicateMappingTable(const ArrayRef<const uint8_t>& table);
+  void ReleaseMappingTable(const LengthPrefixedArray<uint8_t>* table);
+
+  const LengthPrefixedArray<uint8_t>* DeduplicateVMapTable(const ArrayRef<const uint8_t>& table);
+  void ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* table);
+
+  const LengthPrefixedArray<uint8_t>* DeduplicateGCMap(const ArrayRef<const uint8_t>& gc_map);
+  void ReleaseGCMap(const LengthPrefixedArray<uint8_t>* gc_map);
+
+  const LengthPrefixedArray<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
+  void ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info);
+
+  const LengthPrefixedArray<LinkerPatch>* DeduplicateLinkerPatches(
+      const ArrayRef<const LinkerPatch>& linker_patches);
+  void ReleaseLinkerPatches(const LengthPrefixedArray<LinkerPatch>* linker_patches);
+
+ private:
+  template <typename T, typename DedupeSetType>
+  const LengthPrefixedArray<T>* AllocateOrDeduplicateArray(const ArrayRef<const T>& data,
+                                                           DedupeSetType* dedupe_set);
+
+  template <typename T>
+  void ReleaseArrayIfNotDeduplicated(const LengthPrefixedArray<T>* array);
+
+  // DeDuplication data structures.
+  template <typename ContentType>
+  class DedupeHashFunc;
+
+  template <typename T>
+  class LengthPrefixedArrayAlloc;
+
+  template <typename T>
+  using ArrayDedupeSet = DedupeSet<ArrayRef<const T>,
+                                   LengthPrefixedArray<T>,
+                                   LengthPrefixedArrayAlloc<T>,
+                                   size_t,
+                                   DedupeHashFunc<const T>,
+                                   4>;
+
+  // Swap pool and allocator used for native allocations. May be file-backed. Needs to be first
+  // as other fields rely on this.
+  std::unique_ptr<SwapSpace> swap_space_;
+
+  bool dedupe_enabled_;
+
+  ArrayDedupeSet<uint8_t> dedupe_code_;
+  ArrayDedupeSet<SrcMapElem> dedupe_src_mapping_table_;
+  ArrayDedupeSet<uint8_t> dedupe_mapping_table_;
+  ArrayDedupeSet<uint8_t> dedupe_vmap_table_;
+  ArrayDedupeSet<uint8_t> dedupe_gc_map_;
+  ArrayDedupeSet<uint8_t> dedupe_cfi_info_;
+  ArrayDedupeSet<LinkerPatch> dedupe_linker_patches_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompiledMethodStorage);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_COMPILED_METHOD_STORAGE_H_
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
new file mode 100644
index 0000000..c6dbd24
--- /dev/null
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "compiled_method_storage.h"
+#include "compiled_method.h"
+#include "compiler_driver.h"
+#include "compiler_options.h"
+#include "dex/verification_results.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+
+namespace art {
+
+TEST(CompiledMethodStorage, Deduplicate) {
+  CompilerOptions compiler_options;
+  VerificationResults verification_results(&compiler_options);
+  DexFileToMethodInlinerMap method_inliner_map;
+  CompilerDriver driver(&compiler_options,
+                        &verification_results,
+                        &method_inliner_map,
+                        Compiler::kOptimizing, kNone,
+                        nullptr,
+                        false,
+                        nullptr,
+                        nullptr,
+                        nullptr,
+                        1u,
+                        false,
+                        false,
+                        "",
+                        false,
+                        nullptr,
+                        -1,
+                        "");
+  CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
+
+  ASSERT_TRUE(storage->DedupeEnabled());  // The default.
+
+  const uint8_t raw_code1[] = { 1u, 2u, 3u };
+  const uint8_t raw_code2[] = { 4u, 3u, 2u, 1u };
+  ArrayRef<const uint8_t> code[] = {
+      ArrayRef<const uint8_t>(raw_code1),
+      ArrayRef<const uint8_t>(raw_code2),
+  };
+  const SrcMapElem raw_src_map1[] = { { 1u, 2u }, { 3u, 4u }, { 5u, 6u } };
+  const SrcMapElem raw_src_map2[] = { { 8u, 7u }, { 6u, 5u }, { 4u, 3u }, { 2u, 1u } };
+  ArrayRef<const SrcMapElem> src_map[] = {
+      ArrayRef<const SrcMapElem>(raw_src_map1),
+      ArrayRef<const SrcMapElem>(raw_src_map2),
+  };
+  const uint8_t raw_mapping_table1[] = { 5, 6, 7 };
+  const uint8_t raw_mapping_table2[] = { 7, 6, 5, 4 };
+  ArrayRef<const uint8_t> mapping_table[] = {
+      ArrayRef<const uint8_t>(raw_mapping_table1),
+      ArrayRef<const uint8_t>(raw_mapping_table2),
+  };
+  const uint8_t raw_vmap_table1[] = { 2, 4, 6 };
+  const uint8_t raw_vmap_table2[] = { 7, 5, 3, 1 };
+  ArrayRef<const uint8_t> vmap_table[] = {
+      ArrayRef<const uint8_t>(raw_vmap_table1),
+      ArrayRef<const uint8_t>(raw_vmap_table2),
+  };
+  const uint8_t raw_gc_map1[] = { 9, 8, 7 };
+  const uint8_t raw_gc_map2[] = { 6, 7, 8, 9 };
+  ArrayRef<const uint8_t> gc_map[] = {
+      ArrayRef<const uint8_t>(raw_gc_map1),
+      ArrayRef<const uint8_t>(raw_gc_map2),
+  };
+  const uint8_t raw_cfi_info1[] = { 1, 3, 5 };
+  const uint8_t raw_cfi_info2[] = { 8, 6, 4, 2 };
+  ArrayRef<const uint8_t> cfi_info[] = {
+      ArrayRef<const uint8_t>(raw_cfi_info1),
+      ArrayRef<const uint8_t>(raw_cfi_info2),
+  };
+  const LinkerPatch raw_patches1[] = {
+      LinkerPatch::CodePatch(0u, nullptr, 1u),
+      LinkerPatch::MethodPatch(4u, nullptr, 1u),
+  };
+  const LinkerPatch raw_patches2[] = {
+      LinkerPatch::CodePatch(0u, nullptr, 1u),
+      LinkerPatch::MethodPatch(4u, nullptr, 2u),
+  };
+  ArrayRef<const LinkerPatch> patches[] = {
+      ArrayRef<const LinkerPatch>(raw_patches1),
+      ArrayRef<const LinkerPatch>(raw_patches2),
+  };
+
+  std::vector<CompiledMethod*> compiled_methods;
+  compiled_methods.reserve(1u << 7);
+  for (auto&& c : code) {
+    for (auto&& s : src_map) {
+      for (auto&& m : mapping_table) {
+        for (auto&& v : vmap_table) {
+          for (auto&& g : gc_map) {
+            for (auto&& f : cfi_info) {
+              for (auto&& p : patches) {
+                compiled_methods.push_back(CompiledMethod::SwapAllocCompiledMethod(
+                        &driver, kNone, c, 0u, 0u, 0u, s, m, v, g, f, p));
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  constexpr size_t code_bit = 1u << 6;
+  constexpr size_t src_map_bit = 1u << 5;
+  constexpr size_t mapping_table_bit = 1u << 4;
+  constexpr size_t vmap_table_bit = 1u << 3;
+  constexpr size_t gc_map_bit = 1u << 2;
+  constexpr size_t cfi_info_bit = 1u << 1;
+  constexpr size_t patches_bit = 1u << 0;
+  CHECK_EQ(compiled_methods.size(), 1u << 7);
+  for (size_t i = 0; i != compiled_methods.size(); ++i) {
+    for (size_t j = 0; j != compiled_methods.size(); ++j) {
+      CompiledMethod* lhs = compiled_methods[i];
+      CompiledMethod* rhs = compiled_methods[j];
+      bool same_code = ((i ^ j) & code_bit) == 0u;
+      bool same_src_map = ((i ^ j) & src_map_bit) == 0u;
+      bool same_mapping_table = ((i ^ j) & mapping_table_bit) == 0u;
+      bool same_vmap_table = ((i ^ j) & vmap_table_bit) == 0u;
+      bool same_gc_map = ((i ^ j) & gc_map_bit) == 0u;
+      bool same_cfi_info = ((i ^ j) & cfi_info_bit) == 0u;
+      bool same_patches = ((i ^ j) & patches_bit) == 0u;
+      ASSERT_EQ(same_code, lhs->GetQuickCode().data() == rhs->GetQuickCode().data())
+          << i << " " << j;
+      ASSERT_EQ(same_src_map, lhs->GetSrcMappingTable().data() == rhs->GetSrcMappingTable().data())
+          << i << " " << j;
+      ASSERT_EQ(same_mapping_table, lhs->GetMappingTable().data() == rhs->GetMappingTable().data())
+          << i << " " << j;
+      ASSERT_EQ(same_vmap_table, lhs->GetVmapTable().data() == rhs->GetVmapTable().data())
+          << i << " " << j;
+      ASSERT_EQ(same_gc_map, lhs->GetGcMap().data() == rhs->GetGcMap().data())
+          << i << " " << j;
+      ASSERT_EQ(same_cfi_info, lhs->GetCFIInfo().data() == rhs->GetCFIInfo().data())
+          << i << " " << j;
+      ASSERT_EQ(same_patches, lhs->GetPatches().data() == rhs->GetPatches().data())
+          << i << " " << j;
+    }
+  }
+  for (CompiledMethod* method : compiled_methods) {
+    CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&driver, method);
+  }
+}
+
+}  // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index b956584..8750aa8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -348,9 +348,8 @@
                                const std::string& dump_cfg_file_name, bool dump_cfg_append,
                                CumulativeLogger* timer, int swap_fd,
                                const std::string& profile_file)
-    : swap_space_(swap_fd == -1 ? nullptr : new SwapSpace(swap_fd, 10 * MB)),
-      swap_space_allocator_(new SwapAllocator<void>(swap_space_.get())),
-      profile_present_(false), compiler_options_(compiler_options),
+    : profile_present_(false),
+      compiler_options_(compiler_options),
       verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
       compiler_(Compiler::Create(this, compiler_kind)),
@@ -369,7 +368,6 @@
       had_hard_verifier_failure_(false),
       thread_count_(thread_count),
       stats_(new AOTCompilationStats),
-      dedupe_enabled_(true),
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
       dump_cfg_file_name_(dump_cfg_file_name),
@@ -377,12 +375,7 @@
       timings_logger_(timer),
       compiler_context_(nullptr),
       support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64),
-      dedupe_code_("dedupe code", *swap_space_allocator_),
-      dedupe_src_mapping_table_("dedupe source mapping table", *swap_space_allocator_),
-      dedupe_mapping_table_("dedupe mapping table", *swap_space_allocator_),
-      dedupe_vmap_table_("dedupe vmap table", *swap_space_allocator_),
-      dedupe_gc_map_("dedupe gc map", *swap_space_allocator_),
-      dedupe_cfi_info_("dedupe cfi info", *swap_space_allocator_) {
+      compiled_method_storage_(swap_fd) {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
@@ -402,36 +395,6 @@
   }
 }
 
-SwapVector<uint8_t>* CompilerDriver::DeduplicateCode(const ArrayRef<const uint8_t>& code) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_code_.Add(Thread::Current(), code);
-}
-
-SwapSrcMap* CompilerDriver::DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_src_mapping_table_.Add(Thread::Current(), src_map);
-}
-
-SwapVector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const ArrayRef<const uint8_t>& code) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_mapping_table_.Add(Thread::Current(), code);
-}
-
-SwapVector<uint8_t>* CompilerDriver::DeduplicateVMapTable(const ArrayRef<const uint8_t>& code) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_vmap_table_.Add(Thread::Current(), code);
-}
-
-SwapVector<uint8_t>* CompilerDriver::DeduplicateGCMap(const ArrayRef<const uint8_t>& code) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_gc_map_.Add(Thread::Current(), code);
-}
-
-SwapVector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info) {
-  DCHECK(dedupe_enabled_);
-  return dedupe_cfi_info_.Add(Thread::Current(), cfi_info);
-}
-
 CompilerDriver::~CompilerDriver() {
   Thread* self = Thread::Current();
   {
@@ -447,6 +410,7 @@
   compiler_->UnInit();
 }
 
+
 #define CREATE_TRAMPOLINE(type, abi, offset) \
     if (Is64BitInstructionSet(instruction_set_)) { \
       return CreateTrampoline64(instruction_set_, abi, \
@@ -2642,16 +2606,7 @@
   oss << " native alloc=" << PrettySize(allocated_space) << " free="
       << PrettySize(free_space);
 #endif
-  if (swap_space_.get() != nullptr) {
-    oss << " swap=" << PrettySize(swap_space_->GetSize());
-  }
-  if (extended) {
-    oss << "\nCode dedupe: " << dedupe_code_.DumpStats();
-    oss << "\nMapping table dedupe: " << dedupe_mapping_table_.DumpStats();
-    oss << "\nVmap table dedupe: " << dedupe_vmap_table_.DumpStats();
-    oss << "\nGC map dedupe: " << dedupe_gc_map_.DumpStats();
-    oss << "\nCFI info dedupe: " << dedupe_cfi_info_.DumpStats();
-  }
+  compiled_method_storage_.DumpMemoryUsage(oss, extended);
   return oss.str();
 }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 0dc8261..485cdcf 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -30,6 +30,7 @@
 #include "class_reference.h"
 #include "compiler.h"
 #include "dex_file.h"
+#include "driver/compiled_method_storage.h"
 #include "invoke_type.h"
 #include "method_reference.h"
 #include "mirror/class.h"  // For mirror::Class::Status.
@@ -38,10 +39,7 @@
 #include "runtime.h"
 #include "safe_map.h"
 #include "thread_pool.h"
-#include "utils/array_ref.h"
-#include "utils/dedupe_set.h"
 #include "utils/dex_cache_arrays_layout.h"
-#include "utils/swap_space.h"
 
 namespace art {
 
@@ -80,8 +78,6 @@
   kQuickAbi
 };
 
-static constexpr bool kUseMurmur3Hash = true;
-
 class CompilerDriver {
  public:
   // Create a compiler targeting the requested "instruction_set".
@@ -388,10 +384,6 @@
     support_boot_image_fixup_ = support_boot_image_fixup;
   }
 
-  SwapAllocator<void>& GetSwapSpaceAllocator() {
-    return *swap_space_allocator_.get();
-  }
-
   bool WriteElf(const std::string& android_root,
                 bool is_host,
                 const std::vector<const DexFile*>& dex_files,
@@ -431,10 +423,10 @@
   }
 
   void SetDedupeEnabled(bool dedupe_enabled) {
-    dedupe_enabled_ = dedupe_enabled;
+    compiled_method_storage_.SetDedupeEnabled(dedupe_enabled);
   }
   bool DedupeEnabled() const {
-    return dedupe_enabled_;
+    return compiled_method_storage_.DedupeEnabled();
   }
 
   // Checks if class specified by type_idx is one of the image_classes_
@@ -455,13 +447,6 @@
                                        uint16_t class_def_idx,
                                        const DexFile& dex_file) const;
 
-  SwapVector<uint8_t>* DeduplicateCode(const ArrayRef<const uint8_t>& code);
-  SwapSrcMap* DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map);
-  SwapVector<uint8_t>* DeduplicateMappingTable(const ArrayRef<const uint8_t>& code);
-  SwapVector<uint8_t>* DeduplicateVMapTable(const ArrayRef<const uint8_t>& code);
-  SwapVector<uint8_t>* DeduplicateGCMap(const ArrayRef<const uint8_t>& code);
-  SwapVector<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
-
   // Should the compiler run on this method given profile information?
   bool SkipCompilation(const std::string& method_name);
 
@@ -479,6 +464,10 @@
     return compiler_kind_;
   }
 
+  CompiledMethodStorage* GetCompiledMethodStorage() {
+    return &compiled_method_storage_;
+  }
+
  private:
   // Return whether the declaring class of `resolved_member` is
   // available to `referrer_class` for read or write access using two
@@ -599,11 +588,6 @@
                       ThreadPool* thread_pool, TimingLogger* timings)
       REQUIRES(!Locks::mutator_lock_);
 
-  // Swap pool and allocator used for native allocations. May be file-backed. Needs to be first
-  // as other fields rely on this.
-  std::unique_ptr<SwapSpace> swap_space_;
-  std::unique_ptr<SwapAllocator<void> > swap_space_allocator_;
-
   ProfileFile profile_file_;
   bool profile_present_;
 
@@ -663,7 +647,6 @@
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
 
-  bool dedupe_enabled_;
   bool dump_stats_;
   const bool dump_passes_;
   const std::string dump_cfg_file_name_;
@@ -678,93 +661,7 @@
 
   bool support_boot_image_fixup_;
 
-  // DeDuplication data structures, these own the corresponding byte arrays.
-  template <typename ContentType>
-  class DedupeHashFunc {
-   public:
-    size_t operator()(const ArrayRef<ContentType>& array) const {
-      const uint8_t* data = reinterpret_cast<const uint8_t*>(array.data());
-      static_assert(IsPowerOfTwo(sizeof(ContentType)),
-          "ContentType is not power of two, don't know whether array layout is as assumed");
-      uint32_t len = sizeof(ContentType) * array.size();
-      if (kUseMurmur3Hash) {
-        static constexpr uint32_t c1 = 0xcc9e2d51;
-        static constexpr uint32_t c2 = 0x1b873593;
-        static constexpr uint32_t r1 = 15;
-        static constexpr uint32_t r2 = 13;
-        static constexpr uint32_t m = 5;
-        static constexpr uint32_t n = 0xe6546b64;
-
-        uint32_t hash = 0;
-
-        const int nblocks = len / 4;
-        typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
-        const unaligned_uint32_t *blocks = reinterpret_cast<const uint32_t*>(data);
-        int i;
-        for (i = 0; i < nblocks; i++) {
-          uint32_t k = blocks[i];
-          k *= c1;
-          k = (k << r1) | (k >> (32 - r1));
-          k *= c2;
-
-          hash ^= k;
-          hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
-        }
-
-        const uint8_t *tail = reinterpret_cast<const uint8_t*>(data + nblocks * 4);
-        uint32_t k1 = 0;
-
-        switch (len & 3) {
-          case 3:
-            k1 ^= tail[2] << 16;
-            FALLTHROUGH_INTENDED;
-          case 2:
-            k1 ^= tail[1] << 8;
-            FALLTHROUGH_INTENDED;
-          case 1:
-            k1 ^= tail[0];
-
-            k1 *= c1;
-            k1 = (k1 << r1) | (k1 >> (32 - r1));
-            k1 *= c2;
-            hash ^= k1;
-        }
-
-        hash ^= len;
-        hash ^= (hash >> 16);
-        hash *= 0x85ebca6b;
-        hash ^= (hash >> 13);
-        hash *= 0xc2b2ae35;
-        hash ^= (hash >> 16);
-
-        return hash;
-      } else {
-        size_t hash = 0x811c9dc5;
-        for (uint32_t i = 0; i < len; ++i) {
-          hash = (hash * 16777619) ^ data[i];
-        }
-        hash += hash << 13;
-        hash ^= hash >> 7;
-        hash += hash << 3;
-        hash ^= hash >> 17;
-        hash += hash << 5;
-        return hash;
-      }
-    }
-  };
-
-  DedupeSet<ArrayRef<const uint8_t>,
-            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_code_;
-  DedupeSet<ArrayRef<SrcMapElem>,
-            SwapSrcMap, size_t, DedupeHashFunc<SrcMapElem>, 4> dedupe_src_mapping_table_;
-  DedupeSet<ArrayRef<const uint8_t>,
-            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_mapping_table_;
-  DedupeSet<ArrayRef<const uint8_t>,
-            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_vmap_table_;
-  DedupeSet<ArrayRef<const uint8_t>,
-            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_gc_map_;
-  DedupeSet<ArrayRef<const uint8_t>,
-            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_cfi_info_;
+  CompiledMethodStorage compiled_method_storage_;
 
   friend class CompileClassVisitor;
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index a07d27c..3ba380e 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -126,7 +126,7 @@
                      initial_opcodes, kCFIFormat, &debug_frame_data_);
   std::vector<uintptr_t> debug_frame_patches;
   std::vector<uintptr_t> expected_patches { 28 };  // NOLINT
-  WriteDebugFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
+  WriteDebugFrameFDE(is64bit, 0, 0x01000000, 0x01000000, ArrayRef<const uint8_t>(*opcodes.data()),
                      kCFIFormat, &debug_frame_data_, &debug_frame_patches);
 
   EXPECT_EQ(expected_patches, debug_frame_patches);
@@ -142,7 +142,8 @@
   std::vector<uintptr_t> debug_frame_patches;
   std::vector<uintptr_t> expected_patches { 32 };  // NOLINT
   WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
-                     opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
+                     ArrayRef<const uint8_t>(*opcodes.data()),
+                     kCFIFormat, &debug_frame_data_, &debug_frame_patches);
   DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
 
   EXPECT_EQ(expected_patches, debug_frame_patches);
@@ -179,7 +180,8 @@
                      initial_opcodes, kCFIFormat, &debug_frame_data_);
   std::vector<uintptr_t> debug_frame_patches;
   WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
-                     opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
+                     ArrayRef<const uint8_t>(*opcodes.data()),
+                     kCFIFormat, &debug_frame_data_, &debug_frame_patches);
 
   CheckObjdumpOutput(is64bit, "-W");
 }
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index b7eff19..f3fba4b 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -25,6 +25,7 @@
 #include "dwarf/dwarf_constants.h"
 #include "dwarf/register.h"
 #include "dwarf/writer.h"
+#include "utils/array_ref.h"
 
 namespace art {
 namespace dwarf {
@@ -70,21 +71,19 @@
       writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata4);  // R: Pointer encoding.
     }
   }
-  writer.PushData(opcodes.data());
+  writer.PushData(*opcodes.data());
   writer.Pad(is64bit ? 8 : 4);
   writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
 }
 
 // Write frame description entry (FDE) to .debug_frame or .eh_frame section.
-template<typename Vector>
+inline
 void WriteDebugFrameFDE(bool is64bit, size_t cie_offset,
                         uint64_t initial_address, uint64_t address_range,
-                        const Vector* opcodes,
+                        const ArrayRef<const uint8_t>& opcodes,
                         CFIFormat format,
                         std::vector<uint8_t>* debug_frame,
                         std::vector<uintptr_t>* debug_frame_patches) {
-  static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
-
   Writer<> writer(debug_frame);
   size_t fde_header_start = writer.data()->size();
   writer.PushUint32(0);  // Length placeholder.
@@ -125,7 +124,7 @@
   writer.PushUint32(debug_abbrev_offset);
   writer.PushUint8(entries.Is64bit() ? 8 : 4);
   size_t entries_offset = writer.data()->size();
-  writer.PushData(entries.data());
+  writer.PushData(*entries.data());
   writer.UpdateUint32(start, writer.data()->size() - start - 4);
   // Copy patch locations and make them relative to .debug_info section.
   for (uintptr_t patch_location : entries.GetPatchLocations()) {
@@ -181,7 +180,7 @@
   writer.PushUint8(0);  // Terminate file list.
   writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4);
   size_t opcodes_offset = writer.data()->size();
-  writer.PushData(opcodes.data());
+  writer.PushData(*opcodes.data());
   writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4);
   // Copy patch locations and make them relative to .debug_line section.
   for (uintptr_t patch_location : opcodes.GetPatchLocations()) {
diff --git a/compiler/dwarf/writer.h b/compiler/dwarf/writer.h
index 42c32c4..00b9dfa 100644
--- a/compiler/dwarf/writer.h
+++ b/compiler/dwarf/writer.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_DWARF_WRITER_H_
 #define ART_COMPILER_DWARF_WRITER_H_
 
+#include <type_traits>
 #include <vector>
 #include "base/bit_utils.h"
 #include "base/logging.h"
@@ -119,9 +120,10 @@
   }
 
   template<typename Vector2>
-  void PushData(const Vector2* buffer) {
-    static_assert(std::is_same<typename Vector2::value_type, uint8_t>::value, "Invalid value type");
-    data_->insert(data_->end(), buffer->begin(), buffer->end());
+  void PushData(const Vector2& buffer) {
+    static_assert(std::is_same<typename std::add_const<typename Vector::value_type>::type,
+                               const uint8_t>::value, "Invalid value type");
+    data_->insert(data_->end(), buffer.begin(), buffer.end());
   }
 
   void UpdateUint32(size_t offset, uint32_t value) {
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index c10ffeb..3a9e312 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -182,8 +182,8 @@
   WriteDebugFrameCIE(isa, address_type, format, debug_frame);
   for (const OatWriter::DebugInfo& mi : method_infos) {
     if (!mi.deduped_) {  // Only one FDE per unique address.
-      const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo();
-      if (opcodes != nullptr) {
+      ArrayRef<const uint8_t> opcodes = mi.compiled_method_->GetCFIInfo();
+      if (!opcodes.empty()) {
         address_to_fde_offset_map.emplace(mi.low_pc_, debug_frame->size());
         WriteDebugFrameFDE(Is64BitInstructionSet(isa), cie_offset,
                            mi.low_pc_, mi.high_pc_ - mi.low_pc_,
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 4310be6..0e5a97f 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -796,7 +796,7 @@
                   offset, kNativeObjectRelocationTypeArtFieldArray });
           offset += header_size;
           // Forward individual fields so that we can quickly find where they belong.
-          for (size_t i = 0, count = cur_fields->Length(); i < count; ++i) {
+          for (size_t i = 0, count = cur_fields->size(); i < count; ++i) {
             // Need to forward arrays separate of fields.
             ArtField* field = &cur_fields->At(i);
             auto it2 = native_object_relocations_.find(field);
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 3d1b42f..a47c601 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -231,39 +231,39 @@
                                  OatFile::OatMethod* out_method) {
   Runtime* runtime = Runtime::Current();
   JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
-  const auto* quick_code = compiled_method->GetQuickCode();
-  if (quick_code == nullptr) {
+  auto const quick_code = compiled_method->GetQuickCode();
+  if (quick_code.empty()) {
     return false;
   }
-  const auto code_size = quick_code->size();
+  const auto code_size = quick_code.size();
   Thread* const self = Thread::Current();
-  auto* const mapping_table = compiled_method->GetMappingTable();
-  auto* const vmap_table = compiled_method->GetVmapTable();
-  auto* const gc_map = compiled_method->GetGcMap();
+  auto const mapping_table = compiled_method->GetMappingTable();
+  auto const vmap_table = compiled_method->GetVmapTable();
+  auto const gc_map = compiled_method->GetGcMap();
   uint8_t* mapping_table_ptr = nullptr;
   uint8_t* vmap_table_ptr = nullptr;
   uint8_t* gc_map_ptr = nullptr;
 
-  if (mapping_table != nullptr) {
+  if (!mapping_table.empty()) {
     // Write out pre-header stuff.
     mapping_table_ptr = code_cache->AddDataArray(
-        self, mapping_table->data(), mapping_table->data() + mapping_table->size());
+        self, mapping_table.data(), mapping_table.data() + mapping_table.size());
     if (mapping_table_ptr == nullptr) {
       return false;  // Out of data cache.
     }
   }
 
-  if (vmap_table != nullptr) {
+  if (!vmap_table.empty()) {
     vmap_table_ptr = code_cache->AddDataArray(
-        self, vmap_table->data(), vmap_table->data() + vmap_table->size());
+        self, vmap_table.data(), vmap_table.data() + vmap_table.size());
     if (vmap_table_ptr == nullptr) {
       return false;  // Out of data cache.
     }
   }
 
-  if (gc_map != nullptr) {
+  if (!gc_map.empty()) {
     gc_map_ptr = code_cache->AddDataArray(
-        self, gc_map->data(), gc_map->data() + gc_map->size());
+        self, gc_map.data(), gc_map.data() + gc_map.size());
     if (gc_map_ptr == nullptr) {
       return false;  // Out of data cache.
     }
@@ -276,8 +276,8 @@
                                                compiled_method->GetFrameSizeInBytes(),
                                                compiled_method->GetCoreSpillMask(),
                                                compiled_method->GetFpSpillMask(),
-                                               compiled_method->GetQuickCode()->data(),
-                                               compiled_method->GetQuickCode()->size());
+                                               compiled_method->GetQuickCode().data(),
+                                               compiled_method->GetQuickCode().size());
 
   if (code == nullptr) {
     return false;
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 34f0802..52a2382 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -487,7 +487,7 @@
                                                  frame_size,
                                                  main_jni_conv->CoreSpillMask(),
                                                  main_jni_conv->FpSpillMask(),
-                                                 nullptr,  // src_mapping_table.
+                                                 ArrayRef<const SrcMapElem>(),
                                                  ArrayRef<const uint8_t>(),  // mapping_table.
                                                  ArrayRef<const uint8_t>(),  // vmap_table.
                                                  ArrayRef<const uint8_t>(),  // native_gc_map.
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index cb9ea38..ac38f3d 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -85,8 +85,7 @@
                                                       const CompiledMethod* compiled_method,
                                                       MethodReference method_ref,
                                                       uint32_t max_extra_space) {
-  DCHECK(compiled_method->GetQuickCode() != nullptr);
-  uint32_t quick_code_size = compiled_method->GetQuickCode()->size();
+  uint32_t quick_code_size = compiled_method->GetQuickCode().size();
   uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader);
   uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size);
   // Adjust for extra space required by the subclass.
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 6f234a8..57018af 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -74,7 +74,7 @@
   // Now that we have the actual offset where the code will be placed, locate the ADRP insns
   // that actually require the thunk.
   uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader);
-  ArrayRef<const uint8_t> code(*compiled_method->GetQuickCode());
+  ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
   uint32_t thunk_offset = compiled_method->AlignCode(quick_code_offset + code.size());
   DCHECK(compiled_method != nullptr);
   for (const LinkerPatch& patch : compiled_method->GetPatches()) {
diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc
index 857d584..2a426b5 100644
--- a/compiler/linker/arm64/relative_patcher_arm64_test.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc
@@ -237,7 +237,7 @@
     CHECK(!compiled_method_refs_.empty());
     CHECK_EQ(compiled_method_refs_[0].dex_method_index, 1u);
     CHECK_EQ(compiled_method_refs_.size(), compiled_methods_.size());
-    uint32_t method1_size = compiled_methods_[0]->GetQuickCode()->size();
+    uint32_t method1_size = compiled_methods_[0]->GetQuickCode().size();
     uint32_t thunk_offset = CompiledCode::AlignCode(method1_offset + method1_size, kArm64);
     uint32_t b_diff = thunk_offset - (method1_offset + num_nops * 4u);
     ASSERT_EQ(b_diff & 3u, 0u);
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index e357662..92cf8ca 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -74,8 +74,8 @@
     compiled_method_refs_.push_back(method_ref);
     compiled_methods_.emplace_back(new CompiledMethod(
         &driver_, instruction_set_, code,
-        0u, 0u, 0u, nullptr, ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(),
-        ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(),
+        0u, 0u, 0u, ArrayRef<const SrcMapElem>(), ArrayRef<const uint8_t>(),
+        ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(),
         patches));
   }
 
@@ -93,7 +93,7 @@
 
       offset += sizeof(OatQuickMethodHeader);
       uint32_t quick_code_offset = offset + compiled_method->CodeDelta();
-      const auto& code = *compiled_method->GetQuickCode();
+      const auto code = compiled_method->GetQuickCode();
       offset += code.size();
 
       method_offset_map_.map.Put(compiled_method_refs_[idx], quick_code_offset);
@@ -125,7 +125,7 @@
 
       out_.WriteFully(dummy_header, sizeof(OatQuickMethodHeader));
       offset += sizeof(OatQuickMethodHeader);
-      ArrayRef<const uint8_t> code(*compiled_method->GetQuickCode());
+      ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
       if (!compiled_method->GetPatches().empty()) {
         patched_code_.assign(code.begin(), code.end());
         code = ArrayRef<const uint8_t>(patched_code_);
@@ -164,7 +164,7 @@
       ++idx;
     }
     CHECK_NE(idx, compiled_method_refs_.size());
-    CHECK_EQ(compiled_methods_[idx]->GetQuickCode()->size(), expected_code.size());
+    CHECK_EQ(compiled_methods_[idx]->GetQuickCode().size(), expected_code.size());
 
     auto result = method_offset_map_.FindMethodOffset(method_ref);
     CHECK(result.first);  // Must have been linked.
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 2d9d91a..06576cc 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -63,9 +63,9 @@
       EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
       uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2);
       quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
-      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      EXPECT_TRUE(quick_code != nullptr);
-      size_t code_size = quick_code->size() * sizeof(quick_code[0]);
+      ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+      EXPECT_FALSE(quick_code.empty());
+      size_t code_size = quick_code.size() * sizeof(quick_code[0]);
       EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size))
           << PrettyMethod(method) << " " << code_size;
       CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size));
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 640698b..dcb23bf 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -172,7 +172,7 @@
 }
 
 struct OatWriter::GcMapDataAccess {
-  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
     return compiled_method->GetGcMap();
   }
 
@@ -194,7 +194,7 @@
 };
 
 struct OatWriter::MappingTableDataAccess {
-  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
     return compiled_method->GetMappingTable();
   }
 
@@ -216,7 +216,7 @@
 };
 
 struct OatWriter::VmapTableDataAccess {
-  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
     return compiled_method->GetVmapTable();
   }
 
@@ -388,8 +388,8 @@
       // Derived from CompiledMethod.
       uint32_t quick_code_offset = 0;
 
-      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      uint32_t code_size = quick_code->size() * sizeof(uint8_t);
+      ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+      uint32_t code_size = quick_code.size() * sizeof(uint8_t);
       uint32_t thumb_offset = compiled_method->CodeDelta();
 
       // Deduplicate code arrays if we are not producing debuggable code.
@@ -428,7 +428,7 @@
       uint32_t vmap_table_offset = method_header->vmap_table_offset_;
       // If we don't have quick code, then we must have a vmap, as that is how the dex2dex
       // compiler records its transformations.
-      DCHECK(quick_code != nullptr || vmap_table_offset != 0);
+      DCHECK(!quick_code.empty() || vmap_table_offset != 0);
       uint32_t gc_map_offset = method_header->gc_map_offset_;
       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
       // to 0-offset and we need to adjust it by code_offset.
@@ -496,12 +496,12 @@
         } else {
           status = mirror::Class::kStatusNotReady;
         }
-        const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
-        if (gc_map != nullptr) {
-          size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
+        ArrayRef<const uint8_t> gc_map = compiled_method->GetGcMap();
+        if (!gc_map.empty()) {
+          size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
           bool is_native = it.MemberIsNative();
           CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
-              << gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
+              << gc_map_size << " " << (is_native ? "true" : "false") << " "
               << (status < mirror::Class::kStatusVerified) << " " << status << " "
               << PrettyMethod(it.GetMemberIndex(), *dex_file_);
         }
@@ -519,30 +519,22 @@
  private:
   struct CodeOffsetsKeyComparator {
     bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
-      if (lhs->GetQuickCode() != rhs->GetQuickCode()) {
-        return lhs->GetQuickCode() < rhs->GetQuickCode();
+      // Code is deduplicated by CompilerDriver, compare only data pointers.
+      if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
+        return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
       }
       // If the code is the same, all other fields are likely to be the same as well.
-      if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) {
-        return lhs->GetMappingTable() < rhs->GetMappingTable();
+      if (UNLIKELY(lhs->GetMappingTable().data() != rhs->GetMappingTable().data())) {
+        return lhs->GetMappingTable().data() < rhs->GetMappingTable().data();
       }
-      if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) {
-        return lhs->GetVmapTable() < rhs->GetVmapTable();
+      if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
+        return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
       }
-      if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) {
-        return lhs->GetGcMap() < rhs->GetGcMap();
+      if (UNLIKELY(lhs->GetGcMap().data() != rhs->GetGcMap().data())) {
+        return lhs->GetGcMap().data() < rhs->GetGcMap().data();
       }
-      const auto& lhs_patches = lhs->GetPatches();
-      const auto& rhs_patches = rhs->GetPatches();
-      if (UNLIKELY(lhs_patches.size() != rhs_patches.size())) {
-        return lhs_patches.size() < rhs_patches.size();
-      }
-      auto rit = rhs_patches.begin();
-      for (const LinkerPatch& lpatch : lhs_patches) {
-        if (UNLIKELY(!(lpatch == *rit))) {
-          return lpatch < *rit;
-        }
-        ++rit;
+      if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
+        return lhs->GetPatches().data() < rhs->GetPatches().data();
       }
       return false;
     }
@@ -583,17 +575,17 @@
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
 
-      const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
-      uint32_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
+      ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method);
+      uint32_t map_size = map.size() * sizeof(map[0]);
       if (map_size != 0u) {
-        auto lb = dedupe_map_.lower_bound(map);
-        if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map, lb->first)) {
+        auto lb = dedupe_map_.lower_bound(map.data());
+        if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map.data(), lb->first)) {
           DataAccess::SetOffset(oat_class, method_offsets_index_, lb->second);
         } else {
           DataAccess::SetOffset(oat_class, method_offsets_index_, offset_);
-          dedupe_map_.PutBefore(lb, map, offset_);
+          dedupe_map_.PutBefore(lb, map.data(), offset_);
           offset_ += map_size;
-          writer_->oat_header_->UpdateChecksum(&(*map)[0], map_size);
+          writer_->oat_header_->UpdateChecksum(&map[0], map_size);
         }
       }
       ++method_offsets_index_;
@@ -605,7 +597,7 @@
  private:
   // Deduplication is already done on a pointer basis by the compiler driver,
   // so we can simply compare the pointers to find out if things are duplicated.
-  SafeMap<const SwapVector<uint8_t>*, uint32_t> dedupe_map_;
+  SafeMap<const uint8_t*, uint32_t> dedupe_map_;
 };
 
 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
@@ -647,7 +639,7 @@
       UNREACHABLE();
     }
 
-    if (compiled_method != nullptr && compiled_method->GetQuickCode()->size() != 0) {
+    if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0) {
       method->SetEntryPointFromQuickCompiledCodePtrSize(
           reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
     }
@@ -713,10 +705,8 @@
       size_t file_offset = file_offset_;
       OutputStream* out = out_;
 
-      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      // Need a wrapper if we create a copy for patching.
-      ArrayRef<const uint8_t> wrapped(*quick_code);
-      uint32_t code_size = quick_code->size() * sizeof(uint8_t);
+      ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
+      uint32_t code_size = quick_code.size() * sizeof(uint8_t);
 
       // Deduplicate code arrays.
       const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -753,8 +743,8 @@
         DCHECK_OFFSET_();
 
         if (!compiled_method->GetPatches().empty()) {
-          patched_code_.assign(quick_code->begin(), quick_code->end());
-          wrapped = ArrayRef<const uint8_t>(patched_code_);
+          patched_code_.assign(quick_code.begin(), quick_code.end());
+          quick_code = ArrayRef<const uint8_t>(patched_code_);
           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
             if (patch.Type() == kLinkerPatchCallRelative) {
               // NOTE: Relative calls across oat files are not supported.
@@ -781,8 +771,8 @@
           }
         }
 
-        writer_->oat_header_->UpdateChecksum(wrapped.data(), code_size);
-        if (!out->WriteFully(wrapped.data(), code_size)) {
+        writer_->oat_header_->UpdateChecksum(quick_code.data(), code_size);
+        if (!out->WriteFully(quick_code.data(), code_size)) {
           ReportWriteFailure("method code", it);
           return false;
         }
@@ -947,14 +937,14 @@
       ++method_offsets_index_;
 
       // Write deduplicated map.
-      const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
-      size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
+      ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method);
+      size_t map_size = map.size() * sizeof(map[0]);
       DCHECK((map_size == 0u && map_offset == 0u) ||
             (map_size != 0u && map_offset != 0u && map_offset <= offset_))
           << map_size << " " << map_offset << " " << offset_ << " "
           << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
       if (map_size != 0u && map_offset == offset_) {
-        if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
+        if (UNLIKELY(!out->WriteFully(&map[0], map_size))) {
           ReportWriteFailure(it);
           return false;
         }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index d6f2543..575483c 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -607,7 +607,7 @@
       codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(),
       codegen->GetCoreSpillMask(),
       codegen->GetFpuSpillMask(),
-      &src_mapping_table,
+      ArrayRef<const SrcMapElem>(src_mapping_table),
       ArrayRef<const uint8_t>(),  // mapping_table.
       ArrayRef<const uint8_t>(stack_map),
       ArrayRef<const uint8_t>(),  // native_gc_map.
@@ -652,7 +652,7 @@
       codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(),
       codegen->GetCoreSpillMask(),
       codegen->GetFpuSpillMask(),
-      &src_mapping_table,
+      ArrayRef<const SrcMapElem>(src_mapping_table),
       AlignVectorSize(mapping_table),
       AlignVectorSize(vmap_table),
       AlignVectorSize(gc_map),
diff --git a/compiler/utils/dedupe_set-inl.h b/compiler/utils/dedupe_set-inl.h
new file mode 100644
index 0000000..ac54813
--- /dev/null
+++ b/compiler/utils/dedupe_set-inl.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 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_UTILS_DEDUPE_SET_INL_H_
+#define ART_COMPILER_UTILS_DEDUPE_SET_INL_H_
+
+#include "dedupe_set.h"
+
+#include <algorithm>
+#include <inttypes.h>
+#include <unordered_map>
+
+#include "base/mutex.h"
+#include "base/hash_set.h"
+#include "base/stl_util.h"
+#include "base/stringprintf.h"
+#include "base/time_utils.h"
+
+namespace art {
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+struct DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::Stats {
+  size_t collision_sum = 0u;
+  size_t collision_max = 0u;
+  size_t total_probe_distance = 0u;
+  size_t total_size = 0u;
+};
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+class DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::Shard {
+ public:
+  Shard(const Alloc& alloc, const std::string& lock_name)
+      : alloc_(alloc),
+        lock_name_(lock_name),
+        lock_(lock_name_.c_str()),
+        keys_() {
+  }
+
+  ~Shard() {
+    for (const HashedKey<StoreKey>& key : keys_) {
+      DCHECK(key.Key() != nullptr);
+      alloc_.Destroy(key.Key());
+    }
+  }
+
+  const StoreKey* Add(Thread* self, size_t hash, const InKey& in_key) REQUIRES(!lock_) {
+    MutexLock lock(self, lock_);
+    HashedKey<InKey> hashed_in_key(hash, &in_key);
+    auto it = keys_.Find(hashed_in_key);
+    if (it != keys_.end()) {
+      DCHECK(it->Key() != nullptr);
+      return it->Key();
+    }
+    const StoreKey* store_key = alloc_.Copy(in_key);
+    keys_.Insert(HashedKey<StoreKey> { hash, store_key });
+    return store_key;
+  }
+
+  void UpdateStats(Thread* self, Stats* global_stats) REQUIRES(!lock_) {
+    // HashSet<> doesn't keep entries ordered by hash, so we actually allocate memory
+    // for bookkeeping while collecting the stats.
+    std::unordered_map<HashType, size_t> stats;
+    {
+      MutexLock lock(self, lock_);
+      // Note: The total_probe_distance will be updated with the current state.
+      // It may have been higher before a re-hash.
+      global_stats->total_probe_distance += keys_.TotalProbeDistance();
+      global_stats->total_size += keys_.Size();
+      for (const HashedKey<StoreKey>& key : keys_) {
+        auto it = stats.find(key.Hash());
+        if (it == stats.end()) {
+          stats.insert({key.Hash(), 1u});
+        } else {
+          ++it->second;
+        }
+      }
+    }
+    for (const auto& entry : stats) {
+      size_t number_of_entries = entry.second;
+      if (number_of_entries > 1u) {
+        global_stats->collision_sum += number_of_entries - 1u;
+        global_stats->collision_max = std::max(global_stats->collision_max, number_of_entries);
+      }
+    }
+  }
+
+ private:
+  template <typename T>
+  class HashedKey {
+   public:
+    HashedKey() : hash_(0u), key_(nullptr) { }
+    HashedKey(size_t hash, const T* key) : hash_(hash), key_(key) { }
+
+    size_t Hash() const {
+      return hash_;
+    }
+
+    const T* Key() const {
+      return key_;
+    }
+
+    bool IsEmpty() const {
+      return Key() == nullptr;
+    }
+
+    void MakeEmpty() {
+      key_ = nullptr;
+    }
+
+   private:
+    size_t hash_;
+    const T* key_;
+  };
+
+  class ShardEmptyFn {
+   public:
+    bool IsEmpty(const HashedKey<StoreKey>& key) const {
+      return key.IsEmpty();
+    }
+
+    void MakeEmpty(HashedKey<StoreKey>& key) {
+      key.MakeEmpty();
+    }
+  };
+
+  struct ShardHashFn {
+    template <typename T>
+    size_t operator()(const HashedKey<T>& key) const {
+      return key.Hash();
+    }
+  };
+
+  struct ShardPred {
+    typename std::enable_if<!std::is_same<StoreKey, InKey>::value, bool>::type
+    operator()(const HashedKey<StoreKey>& lhs, const HashedKey<StoreKey>& rhs) const {
+      DCHECK(lhs.Key() != nullptr);
+      DCHECK(rhs.Key() != nullptr);
+      // Rehashing: stored keys are already deduplicated, so we can simply compare key pointers.
+      return lhs.Key() == rhs.Key();
+    }
+
+    template <typename LeftT, typename RightT>
+    bool operator()(const HashedKey<LeftT>& lhs, const HashedKey<RightT>& rhs) const {
+      DCHECK(lhs.Key() != nullptr);
+      DCHECK(rhs.Key() != nullptr);
+      return lhs.Hash() == rhs.Hash() &&
+          lhs.Key()->size() == rhs.Key()->size() &&
+          std::equal(lhs.Key()->begin(), lhs.Key()->end(), rhs.Key()->begin());
+    }
+  };
+
+  Alloc alloc_;
+  const std::string lock_name_;
+  Mutex lock_;
+  HashSet<HashedKey<StoreKey>, ShardEmptyFn, ShardHashFn, ShardPred> keys_ GUARDED_BY(lock_);
+};
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+const StoreKey* DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::Add(
+    Thread* self, const InKey& key) {
+  uint64_t hash_start;
+  if (kIsDebugBuild) {
+    hash_start = NanoTime();
+  }
+  HashType raw_hash = HashFunc()(key);
+  if (kIsDebugBuild) {
+    uint64_t hash_end = NanoTime();
+    hash_time_ += hash_end - hash_start;
+  }
+  HashType shard_hash = raw_hash / kShard;
+  HashType shard_bin = raw_hash % kShard;
+  return shards_[shard_bin]->Add(self, shard_hash, key);
+}
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::DedupeSet(const char* set_name,
+                                                                         const Alloc& alloc)
+    : hash_time_(0) {
+  for (HashType i = 0; i < kShard; ++i) {
+    std::ostringstream oss;
+    oss << set_name << " lock " << i;
+    shards_[i].reset(new Shard(alloc, oss.str()));
+  }
+}
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::~DedupeSet() {
+  // Everything done by member destructors.
+}
+
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
+          HashType kShard>
+std::string DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::DumpStats(
+    Thread* self) const {
+  Stats stats;
+  for (HashType shard = 0; shard < kShard; ++shard) {
+    shards_[shard]->UpdateStats(self, &stats);
+  }
+  return StringPrintf("%zu collisions, %zu max hash collisions, "
+                      "%zu/%zu probe distance, %" PRIu64 " ns hash time",
+                      stats.collision_sum,
+                      stats.collision_max,
+                      stats.total_probe_distance,
+                      stats.total_size,
+                      hash_time_);
+}
+
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_DEDUPE_SET_INL_H_
diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h
index 2c4a689..b62f216 100644
--- a/compiler/utils/dedupe_set.h
+++ b/compiler/utils/dedupe_set.h
@@ -17,151 +17,41 @@
 #ifndef ART_COMPILER_UTILS_DEDUPE_SET_H_
 #define ART_COMPILER_UTILS_DEDUPE_SET_H_
 
-#include <algorithm>
-#include <inttypes.h>
 #include <memory>
-#include <set>
+#include <stdint.h>
 #include <string>
 
-#include "base/mutex.h"
-#include "base/stl_util.h"
-#include "base/stringprintf.h"
-#include "base/time_utils.h"
-#include "utils/swap_space.h"
+#include "base/macros.h"
 
 namespace art {
 
+class Thread;
+
 // A set of Keys that support a HashFunc returning HashType. Used to find duplicates of Key in the
 // Add method. The data-structure is thread-safe through the use of internal locks, it also
 // supports the lock being sharded.
-template <typename InKey, typename StoreKey, typename HashType, typename HashFunc,
+template <typename InKey,
+          typename StoreKey,
+          typename Alloc,
+          typename HashType,
+          typename HashFunc,
           HashType kShard = 1>
 class DedupeSet {
-  typedef std::pair<HashType, const InKey*> HashedInKey;
-  struct HashedKey {
-    StoreKey* store_ptr;
-    union {
-      HashType store_hash;        // Valid if store_ptr != null.
-      const HashedInKey* in_key;  // Valid if store_ptr == null.
-    };
-  };
-
-  class Comparator {
-   public:
-    bool operator()(const HashedKey& a, const HashedKey& b) const {
-      HashType a_hash = (a.store_ptr != nullptr) ? a.store_hash : a.in_key->first;
-      HashType b_hash = (b.store_ptr != nullptr) ? b.store_hash : b.in_key->first;
-      if (a_hash != b_hash) {
-        return a_hash < b_hash;
-      }
-      if (a.store_ptr != nullptr && b.store_ptr != nullptr) {
-        return std::lexicographical_compare(a.store_ptr->begin(), a.store_ptr->end(),
-                                            b.store_ptr->begin(), b.store_ptr->end());
-      } else if (a.store_ptr != nullptr && b.store_ptr == nullptr) {
-        return std::lexicographical_compare(a.store_ptr->begin(), a.store_ptr->end(),
-                                            b.in_key->second->begin(), b.in_key->second->end());
-      } else if (a.store_ptr == nullptr && b.store_ptr != nullptr) {
-        return std::lexicographical_compare(a.in_key->second->begin(), a.in_key->second->end(),
-                                            b.store_ptr->begin(), b.store_ptr->end());
-      } else {
-        return std::lexicographical_compare(a.in_key->second->begin(), a.in_key->second->end(),
-                                            b.in_key->second->begin(), b.in_key->second->end());
-      }
-    }
-  };
-
  public:
-  StoreKey* Add(Thread* self, const InKey& key) {
-    uint64_t hash_start;
-    if (kIsDebugBuild) {
-      hash_start = NanoTime();
-    }
-    HashType raw_hash = HashFunc()(key);
-    if (kIsDebugBuild) {
-      uint64_t hash_end = NanoTime();
-      hash_time_ += hash_end - hash_start;
-    }
-    HashType shard_hash = raw_hash / kShard;
-    HashType shard_bin = raw_hash % kShard;
-    HashedInKey hashed_in_key(shard_hash, &key);
-    HashedKey hashed_key;
-    hashed_key.store_ptr = nullptr;
-    hashed_key.in_key = &hashed_in_key;
-    MutexLock lock(self, *lock_[shard_bin]);
-    auto it = keys_[shard_bin].find(hashed_key);
-    if (it != keys_[shard_bin].end()) {
-      DCHECK(it->store_ptr != nullptr);
-      return it->store_ptr;
-    }
-    hashed_key.store_ptr = CreateStoreKey(key);
-    hashed_key.store_hash = shard_hash;
-    keys_[shard_bin].insert(hashed_key);
-    return hashed_key.store_ptr;
-  }
+  // Add a new key to the dedupe set if not present. Return the equivalent deduplicated stored key.
+  const StoreKey* Add(Thread* self, const InKey& key);
 
-  DedupeSet(const char* set_name, SwapAllocator<void>& alloc)
-      : allocator_(alloc), hash_time_(0) {
-    for (HashType i = 0; i < kShard; ++i) {
-      std::ostringstream oss;
-      oss << set_name << " lock " << i;
-      lock_name_[i] = oss.str();
-      lock_[i].reset(new Mutex(lock_name_[i].c_str()));
-    }
-  }
+  DedupeSet(const char* set_name, const Alloc& alloc);
 
-  ~DedupeSet() {
-    // Have to manually free all pointers.
-    for (auto& shard : keys_) {
-      for (const auto& hashed_key : shard) {
-        DCHECK(hashed_key.store_ptr != nullptr);
-        DeleteStoreKey(hashed_key.store_ptr);
-      }
-    }
-  }
+  ~DedupeSet();
 
-  std::string DumpStats() const {
-    size_t collision_sum = 0;
-    size_t collision_max = 0;
-    for (HashType shard = 0; shard < kShard; ++shard) {
-      HashType last_hash = 0;
-      size_t collision_cur_max = 0;
-      for (const HashedKey& key : keys_[shard]) {
-        DCHECK(key.store_ptr != nullptr);
-        if (key.store_hash == last_hash) {
-          collision_cur_max++;
-          if (collision_cur_max > 1) {
-            collision_sum++;
-            if (collision_cur_max > collision_max) {
-              collision_max = collision_cur_max;
-            }
-          }
-        } else {
-          collision_cur_max = 1;
-          last_hash = key.store_hash;
-        }
-      }
-    }
-    return StringPrintf("%zu collisions, %zu max bucket size, %" PRIu64 " ns hash time",
-                        collision_sum, collision_max, hash_time_);
-  }
+  std::string DumpStats(Thread* self) const;
 
  private:
-  StoreKey* CreateStoreKey(const InKey& key) {
-    StoreKey* ret = allocator_.allocate(1);
-    allocator_.construct(ret, key.begin(), key.end(), allocator_);
-    return ret;
-  }
+  struct Stats;
+  class Shard;
 
-  void DeleteStoreKey(StoreKey* key) {
-    SwapAllocator<StoreKey> alloc(allocator_);
-    alloc.destroy(key);
-    alloc.deallocate(key, 1);
-  }
-
-  std::string lock_name_[kShard];
-  std::unique_ptr<Mutex> lock_[kShard];
-  std::set<HashedKey, Comparator> keys_[kShard];
-  SwapAllocator<StoreKey> allocator_;
+  std::unique_ptr<Shard> shards_[kShard];
   uint64_t hash_time_;
 
   DISALLOW_COPY_AND_ASSIGN(DedupeSet);
diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc
index 637964e..60a891d 100644
--- a/compiler/utils/dedupe_set_test.cc
+++ b/compiler/utils/dedupe_set_test.cc
@@ -18,15 +18,18 @@
 
 #include <algorithm>
 #include <cstdio>
+#include <vector>
 
+#include "dedupe_set-inl.h"
 #include "gtest/gtest.h"
 #include "thread-inl.h"
+#include "utils/array_ref.h"
 
 namespace art {
 
-class DedupeHashFunc {
+class DedupeSetTestHashFunc {
  public:
-  size_t operator()(const std::vector<uint8_t>& array) const {
+  size_t operator()(const ArrayRef<const uint8_t>& array) const {
     size_t hash = 0;
     for (uint8_t c : array) {
       hash += c;
@@ -36,46 +39,52 @@
     return hash;
   }
 };
+
+class DedupeSetTestAlloc {
+ public:
+  const std::vector<uint8_t>* Copy(const ArrayRef<const uint8_t>& src) {
+    return new std::vector<uint8_t>(src.begin(), src.end());
+  }
+
+  void Destroy(const std::vector<uint8_t>* key) {
+    delete key;
+  }
+};
+
 TEST(DedupeSetTest, Test) {
   Thread* self = Thread::Current();
-  typedef std::vector<uint8_t> ByteArray;
-  SwapAllocator<void> swap(nullptr);
-  DedupeSet<ByteArray, SwapVector<uint8_t>, size_t, DedupeHashFunc> deduplicator("test", swap);
-  SwapVector<uint8_t>* array1;
+  DedupeSetTestAlloc alloc;
+  DedupeSet<ArrayRef<const uint8_t>,
+            std::vector<uint8_t>,
+            DedupeSetTestAlloc,
+            size_t,
+            DedupeSetTestHashFunc> deduplicator("test", alloc);
+  const std::vector<uint8_t>* array1;
   {
-    ByteArray test1;
-    test1.push_back(10);
-    test1.push_back(20);
-    test1.push_back(30);
-    test1.push_back(45);
-
+    uint8_t raw_test1[] = { 10u, 20u, 30u, 45u };
+    ArrayRef<const uint8_t> test1(raw_test1);
     array1 = deduplicator.Add(self, test1);
     ASSERT_NE(array1, nullptr);
     ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array1->begin()));
   }
 
-  SwapVector<uint8_t>* array2;
+  const std::vector<uint8_t>* array2;
   {
-    ByteArray test1;
-    test1.push_back(10);
-    test1.push_back(20);
-    test1.push_back(30);
-    test1.push_back(45);
-    array2 = deduplicator.Add(self, test1);
+    uint8_t raw_test2[] = { 10u, 20u, 30u, 45u };
+    ArrayRef<const uint8_t> test2(raw_test2);
+    array2 = deduplicator.Add(self, test2);
     ASSERT_EQ(array2, array1);
-    ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array2->begin()));
+    ASSERT_TRUE(std::equal(test2.begin(), test2.end(), array2->begin()));
   }
 
-  SwapVector<uint8_t>* array3;
+  const std::vector<uint8_t>* array3;
   {
-    ByteArray test1;
-    test1.push_back(10);
-    test1.push_back(22);
-    test1.push_back(30);
-    test1.push_back(47);
-    array3 = deduplicator.Add(self, test1);
+    uint8_t raw_test3[] = { 10u, 22u, 30u, 47u };
+    ArrayRef<const uint8_t> test3(raw_test3);
+    array3 = deduplicator.Add(self, test3);
     ASSERT_NE(array3, nullptr);
-    ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array3->begin()));
+    ASSERT_NE(array3, array1);
+    ASSERT_TRUE(std::equal(test3.begin(), test3.end(), array3->begin()));
   }
 }
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 81622e1..e253e13 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5325,7 +5325,7 @@
     ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter());
     if (virtuals != old_virtuals) {
       // Maps from heap allocated miranda method to linear alloc miranda method.
-      StrideIterator<ArtMethod> out = virtuals->Begin(method_size, method_alignment);
+      StrideIterator<ArtMethod> out = virtuals->begin(method_size, method_alignment);
       // Copy over the old methods + miranda methods.
       for (auto& m : klass->GetVirtualMethods(image_pointer_size_)) {
         move_table.emplace(&m, &*out);
@@ -5335,7 +5335,7 @@
         ++out;
       }
     }
-    StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment)
+    StrideIterator<ArtMethod> out(virtuals->begin(method_size, method_alignment)
                                       + old_method_count);
     // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and
     // we want the roots of the miranda methods to get visited.
@@ -5367,7 +5367,7 @@
       move_table.emplace(def_method, &new_method);
       ++out;
     }
-    virtuals->SetLength(new_method_count);
+    virtuals->SetSize(new_method_count);
     UpdateClassVirtualMethods(klass.Get(), virtuals);
     // Done copying methods, they are all roots in the class now, so we can end the no thread
     // suspension assert.
@@ -5382,7 +5382,7 @@
       self->AssertPendingOOMException();
       return false;
     }
-    out = virtuals->Begin(method_size, method_alignment) + old_method_count;
+    out = virtuals->begin(method_size, method_alignment) + old_method_count;
     size_t vtable_pos = old_vtable_count;
     for (size_t i = old_method_count; i < new_method_count; ++i) {
       // Leave the declaring class alone as type indices are relative to it
diff --git a/runtime/image.cc b/runtime/image.cc
index 192371f..1bc19ff 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -150,10 +150,10 @@
 void ImageSection::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const {
   for (size_t pos = 0; pos < Size(); ) {
     auto* array = reinterpret_cast<LengthPrefixedArray<ArtField>*>(base + Offset() + pos);
-    for (size_t i = 0; i < array->Length(); ++i) {
+    for (size_t i = 0; i < array->size(); ++i) {
       visitor->Visit(&array->At(i, sizeof(ArtField)));
     }
-    pos += array->ComputeSize(array->Length());
+    pos += array->ComputeSize(array->size());
   }
 }
 
@@ -164,10 +164,10 @@
   const size_t method_size = ArtMethod::Size(pointer_size);
   for (size_t pos = 0; pos < Size(); ) {
     auto* array = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(base + Offset() + pos);
-    for (size_t i = 0; i < array->Length(); ++i) {
+    for (size_t i = 0; i < array->size(); ++i) {
       visitor->Visit(&array->At(i, method_size, method_alignment));
     }
-    pos += array->ComputeSize(array->Length(), method_size, method_alignment);
+    pos += array->ComputeSize(array->size(), method_size, method_alignment);
   }
 }
 
diff --git a/runtime/length_prefixed_array.h b/runtime/length_prefixed_array.h
index 0ff6d7a..e01b6cc 100644
--- a/runtime/length_prefixed_array.h
+++ b/runtime/length_prefixed_array.h
@@ -30,19 +30,34 @@
 class LengthPrefixedArray {
  public:
   explicit LengthPrefixedArray(size_t length)
-      : length_(dchecked_integral_cast<uint32_t>(length)) {}
+      : size_(dchecked_integral_cast<uint32_t>(length)) {}
 
   T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
-    DCHECK_LT(index, length_);
+    DCHECK_LT(index, size_);
     return AtUnchecked(index, element_size, alignment);
   }
 
-  StrideIterator<T> Begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
+  const T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) const {
+    DCHECK_LT(index, size_);
+    return AtUnchecked(index, element_size, alignment);
+  }
+
+  StrideIterator<T> begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
     return StrideIterator<T>(&AtUnchecked(0, element_size, alignment), element_size);
   }
 
-  StrideIterator<T> End(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
-    return StrideIterator<T>(&AtUnchecked(length_, element_size, alignment), element_size);
+  StrideIterator<const T> begin(size_t element_size = sizeof(T),
+                                size_t alignment = alignof(T)) const {
+    return StrideIterator<const T>(&AtUnchecked(0, element_size, alignment), element_size);
+  }
+
+  StrideIterator<T> end(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
+    return StrideIterator<T>(&AtUnchecked(size_, element_size, alignment), element_size);
+  }
+
+  StrideIterator<const T> end(size_t element_size = sizeof(T),
+                              size_t alignment = alignof(T)) const {
+    return StrideIterator<const T>(&AtUnchecked(size_, element_size, alignment), element_size);
   }
 
   static size_t OffsetOfElement(size_t index,
@@ -60,13 +75,13 @@
     return result;
   }
 
-  uint64_t Length() const {
-    return length_;
+  size_t size() const {
+    return size_;
   }
 
   // Update the length but does not reallocate storage.
-  void SetLength(size_t length) {
-    length_ = dchecked_integral_cast<uint32_t>(length);
+  void SetSize(size_t length) {
+    size_ = dchecked_integral_cast<uint32_t>(length);
   }
 
  private:
@@ -75,7 +90,12 @@
         reinterpret_cast<uintptr_t>(this) + OffsetOfElement(index, element_size, alignment));
   }
 
-  uint32_t length_;
+  const T& AtUnchecked(size_t index, size_t element_size, size_t alignment) const {
+    return *reinterpret_cast<T*>(
+        reinterpret_cast<uintptr_t>(this) + OffsetOfElement(index, element_size, alignment));
+  }
+
+  uint32_t size_;
   uint8_t data[0];
 };
 
@@ -84,7 +104,7 @@
 IterationRange<StrideIterator<T>> MakeIterationRangeFromLengthPrefixedArray(
     LengthPrefixedArray<T>* arr, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
   return arr != nullptr ?
-      MakeIterationRange(arr->Begin(element_size, alignment), arr->End(element_size, alignment)) :
+      MakeIterationRange(arr->begin(element_size, alignment), arr->end(element_size, alignment)) :
       MakeEmptyIterationRange(StrideIterator<T>(nullptr, 0));
 }
 
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index a528c3b..19ee7f4 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -928,22 +928,22 @@
 
 inline uint32_t Class::NumDirectMethods() {
   LengthPrefixedArray<ArtMethod>* arr = GetDirectMethodsPtrUnchecked();
-  return arr != nullptr ? arr->Length() : 0u;
+  return arr != nullptr ? arr->size() : 0u;
 }
 
 inline uint32_t Class::NumVirtualMethods() {
   LengthPrefixedArray<ArtMethod>* arr = GetVirtualMethodsPtrUnchecked();
-  return arr != nullptr ? arr->Length() : 0u;
+  return arr != nullptr ? arr->size() : 0u;
 }
 
 inline uint32_t Class::NumInstanceFields() {
   LengthPrefixedArray<ArtField>* arr = GetIFieldsPtrUnchecked();
-  return arr != nullptr ? arr->Length() : 0u;
+  return arr != nullptr ? arr->size() : 0u;
 }
 
 inline uint32_t Class::NumStaticFields() {
   LengthPrefixedArray<ArtField>* arr = GetSFieldsPtrUnchecked();
-  return arr != nullptr ? arr->Length() : 0u;
+  return arr != nullptr ? arr->size() : 0u;
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 53fedab..9d01a1d 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -574,7 +574,7 @@
     return nullptr;
   }
   size_t low = 0;
-  size_t high = fields->Length();
+  size_t high = fields->size();
   ArtField* ret = nullptr;
   while (low < high) {
     size_t mid = (low + high) / 2;
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3a73900..5e42392 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -190,7 +190,7 @@
     return nullptr;
   }
   size_t low = 0;
-  size_t high = fields->Length();
+  size_t high = fields->size();
   const uint16_t* const data = name->GetValue();
   const size_t length = name->GetLength();
   while (low < high) {
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index bc9ba37..57472ad 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -216,10 +216,10 @@
 
   LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetSFieldsPtr();
   ASSERT_TRUE(static_fields0 != nullptr);
-  ASSERT_EQ(2u, static_fields0->Length());
+  ASSERT_EQ(2u, static_fields0->size());
   LengthPrefixedArray<ArtField>* static_fields1 = proxyClass1->GetSFieldsPtr();
   ASSERT_TRUE(static_fields1 != nullptr);
-  ASSERT_EQ(2u, static_fields1->Length());
+  ASSERT_EQ(2u, static_fields1->size());
 
   EXPECT_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get());
   EXPECT_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get());
diff --git a/runtime/stride_iterator.h b/runtime/stride_iterator.h
index a9da51b..ac04c3b 100644
--- a/runtime/stride_iterator.h
+++ b/runtime/stride_iterator.h
@@ -19,6 +19,8 @@
 
 #include <iterator>
 
+#include "base/logging.h"
+
 namespace art {
 
 template<typename T>