Merge "ART: Fix test dependencies and code"
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 8599471..1a2d9aa 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -355,6 +355,7 @@
         "jni/jni_cfi_test.cc",
         "optimizing/codegen_test.cc",
         "optimizing/load_store_analysis_test.cc",
+        "optimizing/load_store_elimination_test.cc",
         "optimizing/optimizing_cfi_test.cc",
         "optimizing/scheduler_test.cc",
     ],
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index 518b0ec..b409eb2 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -20,6 +20,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class_linker-inl.h"
+#include "code_item_accessors-inl.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "dex_instruction.h"
@@ -43,7 +44,7 @@
   typedef bool MatchFn(Matcher* matcher);
 
   template <size_t size>
-  static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]);
+  static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]);
 
   // Match and advance.
 
@@ -62,22 +63,20 @@
   bool IPutOnThis();
 
  private:
-  explicit Matcher(const DexFile::CodeItem* code_item)
+  explicit Matcher(const CodeItemDataAccessor* code_item)
       : code_item_(code_item),
-        instruction_(code_item->Instructions().begin()),
-        pos_(0u),
-        mark_(0u) { }
+        instruction_(code_item->begin()) {}
 
-  static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
+  static bool DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size);
 
-  const DexFile::CodeItem* const code_item_;
+  const CodeItemDataAccessor* const code_item_;
   DexInstructionIterator instruction_;
-  size_t pos_;
-  size_t mark_;
+  size_t pos_ = 0u;
+  size_t mark_ = 0u;
 };
 
 template <size_t size>
-bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) {
+bool Matcher::Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]) {
   return DoMatch(code_item, pattern, size);
 }
 
@@ -122,12 +121,12 @@
 }
 
 bool Matcher::IPutOnThis() {
-  DCHECK_NE(code_item_->ins_size_, 0u);
+  DCHECK_NE(code_item_->InsSize(), 0u);
   return IsInstructionIPut(instruction_->Opcode()) &&
-      instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_;
+      instruction_->VRegB_22c() == code_item_->RegistersSize() - code_item_->InsSize();
 }
 
-bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) {
+bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size) {
   Matcher matcher(code_item);
   while (matcher.pos_ != size) {
     if (!pattern[matcher.pos_](&matcher)) {
@@ -158,7 +157,7 @@
 
 // Return the forwarded arguments and check that all remaining arguments are zero.
 // If the check fails, return static_cast<size_t>(-1).
-size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item,
+size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item,
                                           const Instruction* invoke_direct,
                                           uint16_t zero_vreg_mask) {
   DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
@@ -167,7 +166,7 @@
   uint32_t args[Instruction::kMaxVarArgRegs];
   invoke_direct->GetVarArgs(args);
   uint16_t this_vreg = args[0];
-  DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_);  // Checked by verifier.
+  DCHECK_EQ(this_vreg, code_item->RegistersSize() - code_item->InsSize());  // Checked by verifier.
   size_t forwarded = 1u;
   while (forwarded < number_of_args &&
       args[forwarded] == this_vreg + forwarded &&
@@ -249,7 +248,7 @@
   return true;
 }
 
-bool DoAnalyseConstructor(const DexFile::CodeItem* code_item,
+bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
                           ArtMethod* method,
                           /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -292,17 +291,17 @@
   DCHECK(method->IsConstructor());
   DCHECK(code_item != nullptr);
   if (!method->GetDeclaringClass()->IsVerified() ||
-      code_item->insns_size_in_code_units_ > kMaxCodeUnits ||
-      code_item->registers_size_ > kMaxVRegs ||
+      code_item->InsnsSizeInCodeUnits() > kMaxCodeUnits ||
+      code_item->RegistersSize() > kMaxVRegs ||
       !Matcher::Match(code_item, kConstructorPattern)) {
     return false;
   }
 
   // Verify the invoke, prevent a few odd cases and collect IPUTs.
-  uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
+  uint16_t this_vreg = code_item->RegistersSize() - code_item->InsSize();
   uint16_t zero_vreg_mask = 0u;
 
-  for (const DexInstructionPcPair& pair : code_item->Instructions()) {
+  for (const DexInstructionPcPair& pair : *code_item) {
     const Instruction& instruction = pair.Inst();
     if (instruction.Opcode() == Instruction::RETURN_VOID) {
       break;
@@ -314,7 +313,7 @@
       // We allow forwarding constructors only if they pass more arguments
       // to prevent infinite recursion.
       if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
-          instruction.VRegA_35c() <= code_item->ins_size_) {
+          instruction.VRegA_35c() <= code_item->InsSize()) {
         return false;
       }
       size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
@@ -322,14 +321,13 @@
         return false;
       }
       if (target_method->GetDeclaringClass()->IsObjectClass()) {
-        DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(),
-                  Instruction::RETURN_VOID);
+        DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID);
       } else {
-        const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
-        if (target_code_item == nullptr) {
+        CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method);
+        if (!target_code_item.HasCodeItem()) {
           return false;  // Native constructor?
         }
-        if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) {
+        if (!DoAnalyseConstructor(&target_code_item, target_method, iputs)) {
           return false;
         }
         // Prune IPUTs with zero input.
@@ -365,7 +363,7 @@
 
 }  // anonymous namespace
 
-bool AnalyseConstructor(const DexFile::CodeItem* code_item,
+bool AnalyseConstructor(const CodeItemDataAccessor* code_item,
                         ArtMethod* method,
                         InlineMethod* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -429,27 +427,27 @@
     InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
 
 bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) {
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method);
+  if (!code_item.HasCodeItem()) {
     // Native or abstract.
     return false;
   }
-  return AnalyseMethodCode(code_item,
+  return AnalyseMethodCode(&code_item,
                            MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
                            method->IsStatic(),
                            method,
                            result);
 }
 
-bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseMethodCode(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
   // We currently support only plain return or 2-instruction methods.
 
-  DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
-  Instruction::Code opcode = code_item->Instructions().begin()->Opcode();
+  DCHECK_NE(code_item->InsnsSizeInCodeUnits(), 0u);
+  Instruction::Code opcode = code_item->begin()->Opcode();
 
   switch (opcode) {
     case Instruction::RETURN_VOID:
@@ -518,15 +516,15 @@
       strncmp(method_name, "-", strlen("-")) == 0;
 }
 
-bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseReturnMethod(const CodeItemDataAccessor* code_item,
                                                InlineMethod* result) {
-  DexInstructionIterator return_instruction = code_item->Instructions().begin();
+  DexInstructionIterator return_instruction = code_item->begin();
   Instruction::Code return_opcode = return_instruction->Opcode();
   uint32_t reg = return_instruction->VRegA_11x();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   DCHECK_GE(reg, arg_start);
   DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
-      code_item->registers_size_);
+      code_item->RegistersSize());
 
   if (result != nullptr) {
     result->opcode = kInlineOpReturnArg;
@@ -540,9 +538,9 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseConstMethod(const CodeItemDataAccessor* code_item,
                                               InlineMethod* result) {
-  DexInstructionIterator instruction = code_item->Instructions().begin();
+  DexInstructionIterator instruction = code_item->begin();
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
   if (return_opcode != Instruction::RETURN &&
@@ -551,13 +549,13 @@
   }
 
   int32_t return_reg = return_instruction->VRegA_11x();
-  DCHECK_LT(return_reg, code_item->registers_size_);
+  DCHECK_LT(return_reg, code_item->RegistersSize());
 
   int32_t const_value = instruction->VRegB();
   if (instruction->Opcode() == Instruction::CONST_HIGH16) {
     const_value <<= 16;
   }
-  DCHECK_LT(instruction->VRegA(), code_item->registers_size_);
+  DCHECK_LT(instruction->VRegA(), code_item->RegistersSize());
   if (instruction->VRegA() != return_reg) {
     return false;  // Not returning the value set by const?
   }
@@ -571,12 +569,12 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  DexInstructionIterator instruction = code_item->Instructions().begin();
+  DexInstructionIterator instruction = code_item->begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIGet(opcode));
 
@@ -591,17 +589,17 @@
 
   uint32_t return_reg = return_instruction->VRegA_11x();
   DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
-            code_item->registers_size_);
+            code_item->RegistersSize());
 
   uint32_t dst_reg = instruction->VRegA_22c();
   uint32_t object_reg = instruction->VRegB_22c();
   uint32_t field_idx = instruction->VRegC_22c();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(object_reg, code_item->RegistersSize());
   uint32_t object_arg = object_reg - arg_start;
 
-  DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+  DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize());
   if (dst_reg != return_reg) {
     return false;  // Not returning the value retrieved by IGET?
   }
@@ -635,18 +633,18 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  DexInstructionIterator instruction = code_item->Instructions().begin();
+  DexInstructionIterator instruction = code_item->begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIPut(opcode));
 
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   uint16_t return_arg_plus1 = 0u;
   if (return_opcode != Instruction::RETURN_VOID) {
     if (return_opcode != Instruction::RETURN &&
@@ -658,7 +656,7 @@
     uint32_t return_reg = return_instruction->VRegA_11x();
     DCHECK_GE(return_reg, arg_start);
     DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg,
-              code_item->registers_size_);
+              code_item->RegistersSize());
     return_arg_plus1 = return_reg - arg_start + 1u;
   }
 
@@ -666,9 +664,9 @@
   uint32_t object_reg = instruction->VRegB_22c();
   uint32_t field_idx = instruction->VRegC_22c();
   DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(object_reg, code_item->RegistersSize());
   DCHECK_GE(src_reg, arg_start);
-  DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_);
+  DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->RegistersSize());
   uint32_t object_arg = object_reg - arg_start;
   uint32_t src_arg = src_reg - arg_start;
 
diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h
index a35e97f..cde2147 100644
--- a/compiler/dex/inline_method_analyser.h
+++ b/compiler/dex/inline_method_analyser.h
@@ -30,6 +30,8 @@
 
 namespace art {
 
+class CodeItemDataAccessor;
+
 namespace verifier {
 class MethodVerifier;
 }  // namespace verifier
@@ -121,21 +123,21 @@
   static bool IsSyntheticAccessor(MethodReference ref);
 
  private:
-  static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
+  static bool AnalyseMethodCode(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
                                 InlineMethod* result)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-  static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-  static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+  static bool AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+  static bool AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+  static bool AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
                                 InlineMethod* result)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+  static bool AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8678fab..66806d8 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -83,7 +83,8 @@
       DCHECK(load != nullptr);
       DCHECK(load->IsInstanceFieldGet() ||
              load->IsStaticFieldGet() ||
-             load->IsArrayGet());
+             load->IsArrayGet() ||
+             load->IsVecLoad());
       HInstruction* substitute = substitute_instructions_for_loads_[i];
       DCHECK(substitute != nullptr);
       // Keep tracing substitute till one that's not removed.
@@ -98,7 +99,10 @@
 
     // At this point, stores in possibly_removed_stores_ can be safely removed.
     for (HInstruction* store : possibly_removed_stores_) {
-      DCHECK(store->IsInstanceFieldSet() || store->IsStaticFieldSet() || store->IsArraySet());
+      DCHECK(store->IsInstanceFieldSet() ||
+             store->IsStaticFieldSet() ||
+             store->IsArraySet() ||
+             store->IsVecStore());
       store->GetBlock()->RemoveInstruction(store);
     }
 
@@ -137,7 +141,9 @@
   void KeepIfIsStore(HInstruction* heap_value) {
     if (heap_value == kDefaultHeapValue ||
         heap_value == kUnknownHeapValue ||
-        !(heap_value->IsInstanceFieldSet() || heap_value->IsArraySet())) {
+        !(heap_value->IsInstanceFieldSet() ||
+          heap_value->IsArraySet() ||
+          heap_value->IsVecStore())) {
       return;
     }
     auto idx = std::find(possibly_removed_stores_.begin(),
@@ -320,7 +326,9 @@
       return;
     }
     if (heap_value != kUnknownHeapValue) {
-      if (heap_value->IsInstanceFieldSet() || heap_value->IsArraySet()) {
+      if (heap_value->IsInstanceFieldSet() ||
+          heap_value->IsArraySet() ||
+          heap_value->IsVecStore()) {
         HInstruction* store = heap_value;
         // This load must be from a singleton since it's from the same
         // field/element that a "removed" store puts the value. That store
@@ -416,7 +424,9 @@
 
     if (!same_value) {
       if (possibly_redundant) {
-        DCHECK(instruction->IsInstanceFieldSet() || instruction->IsArraySet());
+        DCHECK(instruction->IsInstanceFieldSet() ||
+               instruction->IsArraySet() ||
+               instruction->IsVecStore());
         // Put the store as the heap value. If the value is loaded from heap
         // by a load later, this store isn't really redundant.
         heap_values[idx] = instruction;
@@ -429,8 +439,24 @@
       if (i == idx) {
         continue;
       }
-      if (heap_values[i] == value) {
-        // Same value should be kept even if aliasing happens.
+      if (heap_values[i] == value && !instruction->IsVecOperation()) {
+        // For field/array, same value should be kept even if aliasing happens.
+        //
+        // For vector values , this is NOT safe. For example:
+        //   packed_data = [0xA, 0xB, 0xC, 0xD];            <-- Different values in each lane.
+        //   VecStore array[i  ,i+1,i+2,i+3] = packed_data;
+        //   VecStore array[i+1,i+2,i+3,i+4] = packed_data; <-- We are here (partial overlap).
+        //   VecLoad  vx = array[i,i+1,i+2,i+3];            <-- Cannot be eliminated.
+        //
+        // TODO: to allow such 'same value' optimization on vector data,
+        // LSA needs to report more fine-grain MAY alias information:
+        // (1) May alias due to two vector data partial overlap.
+        //     e.g. a[i..i+3] and a[i+1,..,i+4].
+        // (2) May alias due to two vector data may complete overlap each other.
+        //     e.g. a[i..i+3] and b[i..i+3].
+        // (3) May alias but the exact relationship between two locations is unknown.
+        //     e.g. a[i..i+3] and b[j..j+3], where values of a,b,i,j are all unknown.
+        // This 'same value' optimization can apply only on case (2).
         continue;
       }
       if (heap_values[i] == kUnknownHeapValue) {
@@ -520,6 +546,32 @@
                      value);
   }
 
+  void VisitVecLoad(HVecLoad* instruction) OVERRIDE {
+    HInstruction* array = instruction->InputAt(0);
+    HInstruction* index = instruction->InputAt(1);
+    size_t vector_length = instruction->GetVectorLength();
+    VisitGetLocation(instruction,
+                     array,
+                     HeapLocation::kInvalidFieldOffset,
+                     index,
+                     vector_length,
+                     HeapLocation::kDeclaringClassDefIndexForArrays);
+  }
+
+  void VisitVecStore(HVecStore* instruction) OVERRIDE {
+    HInstruction* array = instruction->InputAt(0);
+    HInstruction* index = instruction->InputAt(1);
+    HInstruction* value = instruction->InputAt(2);
+    size_t vector_length = instruction->GetVectorLength();
+    VisitSetLocation(instruction,
+                     array,
+                     HeapLocation::kInvalidFieldOffset,
+                     index,
+                     vector_length,
+                     HeapLocation::kDeclaringClassDefIndexForArrays,
+                     value);
+  }
+
   void VisitDeoptimize(HDeoptimize* instruction) {
     const ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
@@ -529,7 +581,9 @@
         continue;
       }
       // A store is kept as the heap value for possibly removed stores.
-      if (heap_value->IsInstanceFieldSet() || heap_value->IsArraySet()) {
+      if (heap_value->IsInstanceFieldSet() ||
+          heap_value->IsArraySet() ||
+          heap_value->IsVecStore()) {
         // Check whether the reference for a store is used by an environment local of
         // HDeoptimize.
         HInstruction* reference = heap_value->InputAt(0);
@@ -687,11 +741,6 @@
     return;
   }
 
-  // TODO: analyze VecLoad/VecStore better.
-  if (graph_->HasSIMD()) {
-    return;
-  }
-
   LSEVisitor lse_visitor(graph_, heap_location_collector, side_effects_, stats_);
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
     lse_visitor.VisitBasicBlock(block);
diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc
new file mode 100644
index 0000000..6f42d96
--- /dev/null
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2017 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 "side_effects_analysis.h"
+#include "load_store_analysis.h"
+#include "load_store_elimination.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+class LoadStoreEliminationTest : public OptimizingUnitTest {
+ public:
+  LoadStoreEliminationTest() : pool_() {}
+
+  void PerformLSE() {
+    graph_->BuildDominatorTree();
+    SideEffectsAnalysis side_effects(graph_);
+    side_effects.Run();
+    LoadStoreAnalysis lsa(graph_);
+    lsa.Run();
+    LoadStoreElimination lse(graph_, side_effects, lsa, nullptr);
+    lse.Run();
+  }
+
+  void CreateTestControlFlowGraph() {
+    graph_ = CreateGraph();
+
+    entry_ = new (GetAllocator()) HBasicBlock(graph_);
+    pre_header_ = new (GetAllocator()) HBasicBlock(graph_);
+    loop_header_ = new (GetAllocator()) HBasicBlock(graph_);
+    loop_body_ = new (GetAllocator()) HBasicBlock(graph_);
+    exit_ = new (GetAllocator()) HBasicBlock(graph_);
+
+    graph_->AddBlock(entry_);
+    graph_->AddBlock(pre_header_);
+    graph_->AddBlock(loop_header_);
+    graph_->AddBlock(loop_body_);
+    graph_->AddBlock(exit_);
+
+    graph_->SetEntryBlock(entry_);
+
+    // This common CFG has been used by all cases in this load_store_elimination_test.
+    //   entry
+    //     |
+    // pre_header
+    //     |
+    // loop_header <--+
+    //     |          |
+    // loop_body -----+
+    //     |
+    //    exit
+
+    entry_->AddSuccessor(pre_header_);
+    pre_header_->AddSuccessor(loop_header_);
+    loop_header_->AddSuccessor(exit_);       // true successor
+    loop_header_->AddSuccessor(loop_body_);  // false successor
+    loop_body_->AddSuccessor(loop_header_);
+
+    HInstruction* c0 = graph_->GetIntConstant(0);
+    HInstruction* c1 = graph_->GetIntConstant(1);
+    HInstruction* c4 = graph_->GetIntConstant(4);
+    HInstruction* c128 = graph_->GetIntConstant(128);
+
+    // entry block has following instructions:
+    // array, i, j, i+1, i+4.
+    array_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
+                                               dex::TypeIndex(0),
+                                               0,
+                                               DataType::Type::kReference);
+    i_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
+                                           dex::TypeIndex(1),
+                                           1,
+                                           DataType::Type::kInt32);
+    j_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
+                                           dex::TypeIndex(1),
+                                           2,
+                                           DataType::Type::kInt32);
+    i_add1_ = new (GetAllocator()) HAdd(DataType::Type::kInt32, i_, c1);
+    i_add4_ = new (GetAllocator()) HAdd(DataType::Type::kInt32, i_, c4);
+    entry_->AddInstruction(array_);
+    entry_->AddInstruction(i_);
+    entry_->AddInstruction(j_);
+    entry_->AddInstruction(i_add1_);
+    entry_->AddInstruction(i_add4_);
+    entry_->AddInstruction(new (GetAllocator()) HGoto());
+
+    // pre_header block
+    pre_header_->AddInstruction(new (GetAllocator()) HGoto());
+
+    // loop header block has following instructions:
+    // phi = 0;
+    // if (phi >= 128);
+    phi_ = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
+    cmp_ = new (GetAllocator()) HGreaterThanOrEqual(phi_, c128);
+    if_ = new (GetAllocator()) HIf(cmp_);
+    loop_header_->AddPhi(phi_);
+    loop_header_->AddInstruction(cmp_);
+    loop_header_->AddInstruction(if_);
+    phi_->AddInput(c0);
+
+    // loop body block has following instructions:
+    // phi++;
+    HInstruction* inc_phi = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_, c1);
+    loop_body_->AddInstruction(inc_phi);
+    loop_body_->AddInstruction(new (GetAllocator()) HGoto());
+    phi_->AddInput(inc_phi);
+
+    // exit block
+    exit_->AddInstruction(new (GetAllocator()) HExit());
+  }
+
+  // To avoid tedious HIR assembly in test functions.
+  HInstruction* AddVecLoad(HBasicBlock* block, HInstruction* array, HInstruction* index) {
+    DCHECK(block != nullptr);
+    DCHECK(array != nullptr);
+    DCHECK(index != nullptr);
+    HInstruction* vload = new (GetAllocator()) HVecLoad(
+        GetAllocator(),
+        array,
+        index,
+        DataType::Type::kInt32,
+        SideEffects::ArrayReadOfType(DataType::Type::kInt32),
+        4,
+        /*is_string_char_at*/ false,
+        kNoDexPc);
+    block->InsertInstructionBefore(vload, block->GetLastInstruction());
+    return vload;
+  }
+
+  HInstruction* AddVecStore(HBasicBlock* block,
+                            HInstruction* array,
+                            HInstruction* index,
+                            HVecOperation* vdata = nullptr) {
+    DCHECK(block != nullptr);
+    DCHECK(array != nullptr);
+    DCHECK(index != nullptr);
+    if (vdata == nullptr) {
+      HInstruction* c1 = graph_->GetIntConstant(1);
+      vdata = new (GetAllocator()) HVecReplicateScalar(GetAllocator(),
+                                                       c1,
+                                                       DataType::Type::kInt32,
+                                                       4,
+                                                       kNoDexPc);
+      block->InsertInstructionBefore(vdata, block->GetLastInstruction());
+    }
+    HInstruction* vstore = new (GetAllocator()) HVecStore(
+        GetAllocator(),
+        array,
+        index,
+        vdata,
+        DataType::Type::kInt32,
+        SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+        4,
+        kNoDexPc);
+    block->InsertInstructionBefore(vstore, block->GetLastInstruction());
+    return vstore;
+  }
+
+  HInstruction* AddArrayGet(HBasicBlock* block, HInstruction* array, HInstruction* index) {
+    DCHECK(block != nullptr);
+    DCHECK(array != nullptr);
+    DCHECK(index != nullptr);
+    HInstruction* get = new (GetAllocator()) HArrayGet(array, index, DataType::Type::kInt32, 0);
+    block->InsertInstructionBefore(get, block->GetLastInstruction());
+    return get;
+  }
+
+  HInstruction* AddArraySet(HBasicBlock* block,
+                            HInstruction* array,
+                            HInstruction* index,
+                            HInstruction* data = nullptr) {
+    DCHECK(block != nullptr);
+    DCHECK(array != nullptr);
+    DCHECK(index != nullptr);
+    if (data == nullptr) {
+      data = graph_->GetIntConstant(1);
+    }
+    HInstruction* store = new (GetAllocator()) HArraySet(array,
+                                                         index,
+                                                         data,
+                                                         DataType::Type::kInt32,
+                                                         0);
+    block->InsertInstructionBefore(store, block->GetLastInstruction());
+    return store;
+  }
+
+  ArenaPool pool_;
+
+  HGraph* graph_;
+  HBasicBlock* entry_;
+  HBasicBlock* pre_header_;
+  HBasicBlock* loop_header_;
+  HBasicBlock* loop_body_;
+  HBasicBlock* exit_;
+
+  HInstruction* array_;
+  HInstruction* i_;
+  HInstruction* j_;
+  HInstruction* i_add1_;
+  HInstruction* i_add4_;
+
+  HPhi* phi_;
+  HInstruction* cmp_;
+  HInstruction* if_;
+};
+
+TEST_F(LoadStoreEliminationTest, ArrayGetSetElimination) {
+  CreateTestControlFlowGraph();
+
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  // array[1] = 1;
+  // x = array[1];  <--- Remove.
+  // y = array[2];
+  // array[1] = 1;  <--- Remove, since it stores same value.
+  // array[i] = 3;  <--- MAY alias.
+  // array[1] = 1;  <--- Cannot remove, even if it stores the same value.
+  AddArraySet(entry_, array_, c1, c1);
+  HInstruction* load1 = AddArrayGet(entry_, array_, c1);
+  HInstruction* load2 = AddArrayGet(entry_, array_, c2);
+  HInstruction* store1 = AddArraySet(entry_, array_, c1, c1);
+  AddArraySet(entry_, array_, i_, c3);
+  HInstruction* store2 = AddArraySet(entry_, array_, c1, c1);
+
+  PerformLSE();
+
+  ASSERT_TRUE(IsRemoved(load1));
+  ASSERT_FALSE(IsRemoved(load2));
+  ASSERT_TRUE(IsRemoved(store1));
+  ASSERT_FALSE(IsRemoved(store2));
+}
+
+TEST_F(LoadStoreEliminationTest, SameHeapValue) {
+  CreateTestControlFlowGraph();
+
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+
+  // Test LSE handling same value stores on array.
+  // array[1] = 1;
+  // array[2] = 1;
+  // array[1] = 1;  <--- Can remove.
+  // array[1] = 2;  <--- Can NOT remove.
+  AddArraySet(entry_, array_, c1, c1);
+  AddArraySet(entry_, array_, c2, c1);
+  HInstruction* store1 = AddArraySet(entry_, array_, c1, c1);
+  HInstruction* store2 = AddArraySet(entry_, array_, c1, c2);
+
+  // Test LSE handling same value stores on vector.
+  // vdata = [0x1, 0x2, 0x3, 0x4, ...]
+  // VecStore array[i...] = vdata;
+  // VecStore array[j...] = vdata;  <--- MAY ALIAS.
+  // VecStore array[i...] = vdata;  <--- Cannot Remove, even if it's same value.
+  AddVecStore(entry_, array_, i_);
+  AddVecStore(entry_, array_, j_);
+  HInstruction* vstore1 = AddVecStore(entry_, array_, i_);
+
+  // VecStore array[i...] = vdata;
+  // VecStore array[i+1...] = vdata;  <--- MAY alias due to partial overlap.
+  // VecStore array[i...] = vdata;    <--- Cannot remove, even if it's same value.
+  AddVecStore(entry_, array_, i_);
+  AddVecStore(entry_, array_, i_add1_);
+  HInstruction* vstore2 = AddVecStore(entry_, array_, i_);
+
+  PerformLSE();
+
+  ASSERT_TRUE(IsRemoved(store1));
+  ASSERT_FALSE(IsRemoved(store2));
+  ASSERT_FALSE(IsRemoved(vstore1));
+  ASSERT_FALSE(IsRemoved(vstore2));
+}
+
+TEST_F(LoadStoreEliminationTest, OverlappingLoadStore) {
+  CreateTestControlFlowGraph();
+
+  HInstruction* c1 = graph_->GetIntConstant(1);
+
+  // Test LSE handling array LSE when there is vector store in between.
+  // a[i] = 1;
+  // .. = a[i];                <-- Remove.
+  // a[i,i+1,i+2,i+3] = data;  <-- PARTIAL OVERLAP !
+  // .. = a[i];                <-- Cannot remove.
+  AddArraySet(entry_, array_, i_, c1);
+  HInstruction* load1 = AddArrayGet(entry_, array_, i_);
+  AddVecStore(entry_, array_, i_);
+  HInstruction* load2 = AddArrayGet(entry_, array_, i_);
+
+  // Test LSE handling vector load/store partial overlap.
+  // a[i,i+1,i+2,i+3] = data;
+  // a[i+4,i+5,i+6,i+7] = data;
+  // .. = a[i,i+1,i+2,i+3];
+  // .. = a[i+4,i+5,i+6,i+7];
+  // a[i+1,i+2,i+3,i+4] = data;  <-- PARTIAL OVERLAP !
+  // .. = a[i,i+1,i+2,i+3];
+  // .. = a[i+4,i+5,i+6,i+7];
+  AddVecStore(entry_, array_, i_);
+  AddVecStore(entry_, array_, i_add4_);
+  HInstruction* vload1 = AddVecLoad(entry_, array_, i_);
+  HInstruction* vload2 = AddVecLoad(entry_, array_, i_add4_);
+  AddVecStore(entry_, array_, i_add1_);
+  HInstruction* vload3 = AddVecLoad(entry_, array_, i_);
+  HInstruction* vload4 = AddVecLoad(entry_, array_, i_add4_);
+
+  // Test LSE handling vector LSE when there is array store in between.
+  // a[i,i+1,i+2,i+3] = data;
+  // a[i+1] = 1;                 <-- PARTIAL OVERLAP !
+  // .. = a[i,i+1,i+2,i+3];
+  AddVecStore(entry_, array_, i_);
+  AddArraySet(entry_, array_, i_, c1);
+  HInstruction* vload5 = AddVecLoad(entry_, array_, i_);
+
+  PerformLSE();
+
+  ASSERT_TRUE(IsRemoved(load1));
+  ASSERT_FALSE(IsRemoved(load2));
+
+  ASSERT_TRUE(IsRemoved(vload1));
+  ASSERT_TRUE(IsRemoved(vload2));
+  ASSERT_FALSE(IsRemoved(vload3));
+  ASSERT_FALSE(IsRemoved(vload4));
+
+  ASSERT_FALSE(IsRemoved(vload5));
+}
+
+// function (int[] a, int j) {
+// a[j] = 1;
+// for (int i=0; i<128; i++) {
+//    /* doesn't do any write */
+// }
+// a[j] = 1;
+TEST_F(LoadStoreEliminationTest, Loop1) {
+  CreateTestControlFlowGraph();
+
+  HInstruction* c1 = graph_->GetIntConstant(1);
+
+  // a[j] = 1
+  AddArraySet(pre_header_, array_, j_, c1);
+
+  // LOOP BODY:
+  // .. = a[i,i+1,i+2,i+3];
+  AddVecLoad(loop_body_, array_, phi_);
+
+  // a[j] = 1;
+  HInstruction* array_set = AddArraySet(exit_, array_, j_, c1);
+
+  PerformLSE();
+
+  ASSERT_TRUE(IsRemoved(array_set));
+}
+
+// function (int[] a, int index) {
+//   a[index] = 1;
+//   int[] b = new int[128];
+//   for (int i=0; i<128; i++) {
+//     a[i,i+1,i+2,i+3] = vdata;
+//     b[i,i+1,i+2,i+3] = a[i,i+1,i+2,i+3];
+//   }
+//   a[index] = 1;
+// }
+TEST_F(LoadStoreEliminationTest, Loop2) {
+  CreateTestControlFlowGraph();
+
+  HInstruction* c0 = graph_->GetIntConstant(0);
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c128 = graph_->GetIntConstant(128);
+
+  HInstruction* array_b = new (GetAllocator()) HNewArray(c0, c128, 0);
+  entry_->AddInstruction(array_b);
+
+  // a[index] = 1;
+  AddArraySet(pre_header_, array_, i_, c1);
+
+  // a[i,i+1,i+2,i+3] = vdata;
+  // b[i,i+1,i+2,i+3] = a[i,i+1,i+2,i+3];
+  AddVecStore(loop_body_, array_, phi_);
+  HInstruction* vload = AddVecLoad(loop_body_, array_, phi_);
+  AddVecStore(loop_body_, array_b, phi_, vload->AsVecLoad());
+
+  // a[index] = 1;
+  HInstruction* a_set = AddArraySet(exit_, array_, i_, c1);
+
+  PerformLSE();
+
+  ASSERT_TRUE(IsRemoved(vload));
+  ASSERT_FALSE(IsRemoved(a_set));   // Cannot remove due to side effect in loop.
+}
+
+}  // namespace art
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index afca26d..c2556aa 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -941,7 +941,7 @@
                class_it.Next()) {
             if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
               for (const DexInstructionPcPair& inst :
-                  class_it.GetMethodCodeItem()->Instructions()) {
+                       class_it.GetMethodCodeItem()->Instructions()) {
                 ASSERT_FALSE(inst->IsQuickened());
               }
             }
diff --git a/runtime/Android.bp b/runtime/Android.bp
index e032238..69e4434 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -567,6 +567,7 @@
         "class_linker_test.cc",
         "class_loader_context_test.cc",
         "class_table_test.cc",
+        "code_item_accessors_test.cc",
         "compiler_filter_test.cc",
         "dex_file_test.cc",
         "dex_file_verifier_test.cc",
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index e1671c9..50913de 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -23,6 +23,7 @@
 #include "base/callee_save_type.h"
 #include "base/logging.h"
 #include "class_linker-inl.h"
+#include "code_item_accessors-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
 #include "dex_file_annotations.h"
@@ -459,6 +460,18 @@
   }
 }
 
+inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() {
+  CodeItemInstructionAccessor accessor(this);
+  return { accessor.begin(),
+           accessor.end() };
+}
+
+inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() {
+  CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this));
+  return { accessor.begin(),
+           accessor.end() };
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 0e98d47..c17eef1 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -22,8 +22,10 @@
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/enums.h"
+#include "base/iteration_range.h"
 #include "base/logging.h"
 #include "dex_file.h"
+#include "dex_instruction_iterator.h"
 #include "gc_root.h"
 #include "modifiers.h"
 #include "obj_ptr.h"
@@ -710,6 +712,15 @@
             "ptr_sized_fields_.entry_point_from_quick_compiled_code_");
   }
 
+  // Returns the dex instructions of the code item for the art method. Must not be called on null
+  // code items.
+  ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Handles a null code item by returning iterators that have a null address.
+  ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
  protected:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class we are a part of.
diff --git a/runtime/base/casts.h b/runtime/base/casts.h
index 0cbabba..92c493a 100644
--- a/runtime/base/casts.h
+++ b/runtime/base/casts.h
@@ -77,6 +77,14 @@
   return static_cast<To>(f);
 }
 
+template<typename To, typename From>     // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) {           // so we only accept references
+  static_assert(std::is_base_of<From, typename std::remove_reference<To>::type>::value,
+                "down_cast unsafe as To is not a subtype of From");
+
+  return static_cast<To>(f);
+}
+
 template <class Dest, class Source>
 inline Dest bit_cast(const Source& source) {
   // Compile time assertion: sizeof(Dest) == sizeof(Source)
diff --git a/runtime/cdex/compact_dex_file.h b/runtime/cdex/compact_dex_file.h
index 8ab9247..f17f8cf 100644
--- a/runtime/cdex/compact_dex_file.h
+++ b/runtime/cdex/compact_dex_file.h
@@ -24,11 +24,18 @@
 // CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage.
 class CompactDexFile : public DexFile {
  public:
+  static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
+  static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
+
   class Header : public DexFile::Header {
     // Same for now.
   };
-  static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
-  static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
+
+  struct CodeItem : public DexFile::CodeItem {
+   private:
+    // TODO: Insert compact dex specific fields here.
+    DISALLOW_COPY_AND_ASSIGN(CodeItem);
+  };
 
   // Write the compact dex specific magic.
   static void WriteMagic(uint8_t* magic);
@@ -44,10 +51,6 @@
   static bool IsVersionValid(const uint8_t* magic);
   virtual bool IsVersionValid() const OVERRIDE;
 
-  bool IsCompactDexFile() const OVERRIDE {
-    return true;
-  }
-
  private:
   // Not supported yet.
   CompactDexFile(const uint8_t* base,
@@ -56,7 +59,13 @@
                  uint32_t location_checksum,
                  const OatDexFile* oat_dex_file,
                  DexFileContainer* container)
-      : DexFile(base, size, location, location_checksum, oat_dex_file, container) {}
+      : DexFile(base,
+                size,
+                location,
+                location_checksum,
+                oat_dex_file,
+                container,
+                /*is_compact_dex*/ true) {}
 
   friend class DexFile;
   friend class DexFileLoader;
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
new file mode 100644
index 0000000..61b5175
--- /dev/null
+++ b/runtime/code_item_accessors-inl.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 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_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+#define ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+
+#include "code_item_accessors.h"
+
+#include "art_method-inl.h"
+#include "cdex/compact_dex_file.h"
+#include "standard_dex_file.h"
+
+namespace art {
+
+inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+  insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
+  insns_ = code_item.insns_;
+}
+
+inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+  insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
+  insns_ = code_item.insns_;
+}
+
+inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
+                                               const DexFile::CodeItem* code_item) {
+  DCHECK(dex_file != nullptr);
+  DCHECK(code_item != nullptr);
+  if (dex_file->IsCompactDexFile()) {
+    Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+  } else {
+    DCHECK(dex_file->IsStandardDexFile());
+    Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+  }
+}
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
+    const DexFile* dex_file,
+    const DexFile::CodeItem* code_item) {
+  Init(dex_file, code_item);
+}
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
+    : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
+  return DexInstructionIterator(insns_, 0u);
+}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
+  return DexInstructionIterator(insns_, insns_size_in_code_units_);
+}
+
+inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable(
+    ArtMethod* method) {
+  DCHECK(method != nullptr);
+  CodeItemInstructionAccessor ret;
+  const DexFile::CodeItem* code_item = method->GetCodeItem();
+  if (code_item != nullptr) {
+    ret.Init(method->GetDexFile(), code_item);
+  } else {
+    DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
+  }
+  return ret;
+}
+
+inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+  CodeItemInstructionAccessor::Init(code_item);
+  registers_size_ = code_item.registers_size_;
+  ins_size_ = code_item.ins_size_;
+  outs_size_ = code_item.outs_size_;
+  tries_size_ = code_item.tries_size_;
+}
+
+inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+  CodeItemInstructionAccessor::Init(code_item);
+  registers_size_ = code_item.registers_size_;
+  ins_size_ = code_item.ins_size_;
+  outs_size_ = code_item.outs_size_;
+  tries_size_ = code_item.tries_size_;
+}
+
+inline void CodeItemDataAccessor::Init(const DexFile* dex_file,
+                                       const DexFile::CodeItem* code_item) {
+  DCHECK(dex_file != nullptr);
+  DCHECK(code_item != nullptr);
+  if (dex_file->IsCompactDexFile()) {
+    CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+  } else {
+    DCHECK(dex_file->IsStandardDexFile());
+    CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+  }
+}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile* dex_file,
+                                                  const DexFile::CodeItem* code_item) {
+  Init(dex_file, code_item);
+}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
+    : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
+  DCHECK(method != nullptr);
+  CodeItemDataAccessor ret;
+  const DexFile::CodeItem* code_item = method->GetCodeItem();
+  if (code_item != nullptr) {
+    ret.Init(method->GetDexFile(), code_item);
+  } else {
+    DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
+  }
+  return ret;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
new file mode 100644
index 0000000..fcece3e
--- /dev/null
+++ b/runtime/code_item_accessors.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump.
+
+#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+#define ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+
+#include "base/mutex.h"
+#include "cdex/compact_dex_file.h"
+#include "dex_file.h"
+#include "dex_instruction_iterator.h"
+#include "standard_dex_file.h"
+
+namespace art {
+
+class ArtMethod;
+
+// Abstracts accesses to the instruction fields of code items for CompactDexFile and
+// StandardDexFile.
+class CodeItemInstructionAccessor {
+ public:
+  ALWAYS_INLINE CodeItemInstructionAccessor(const DexFile* dex_file,
+                                            const DexFile::CodeItem* code_item);
+
+  ALWAYS_INLINE explicit CodeItemInstructionAccessor(ArtMethod* method);
+
+  ALWAYS_INLINE DexInstructionIterator begin() const;
+
+  ALWAYS_INLINE DexInstructionIterator end() const;
+
+  uint32_t InsnsSizeInCodeUnits() const {
+    return insns_size_in_code_units_;
+  }
+
+  const uint16_t* Insns() const {
+    return insns_;
+  }
+
+  // Return true if the accessor has a code item.
+  bool HasCodeItem() const {
+    return Insns() != nullptr;
+  }
+
+  // CreateNullable allows ArtMethods that have a null code item.
+  ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+ protected:
+  CodeItemInstructionAccessor() = default;
+
+  ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+ private:
+  // size of the insns array, in 2 byte code units. 0 if there is no code item.
+  uint32_t insns_size_in_code_units_ = 0;
+
+  // Pointer to the instructions, null if there is no code item.
+  const uint16_t* insns_ = 0;
+};
+
+// Abstracts accesses to code item fields other than debug info for CompactDexFile and
+// StandardDexFile.
+class CodeItemDataAccessor : public CodeItemInstructionAccessor {
+ public:
+  ALWAYS_INLINE CodeItemDataAccessor(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+  ALWAYS_INLINE explicit CodeItemDataAccessor(ArtMethod* method);
+
+  uint16_t RegistersSize() const {
+    return registers_size_;
+  }
+
+  uint16_t InsSize() const {
+    return ins_size_;
+  }
+
+  uint16_t OutsSize() const {
+    return outs_size_;
+  }
+
+  uint16_t TriesSize() const {
+    return tries_size_;
+  }
+
+  // CreateNullable allows ArtMethods that have a null code item.
+  ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+ protected:
+  CodeItemDataAccessor() = default;
+
+  ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+ private:
+  // Fields mirrored from the dex/cdex code item.
+  uint16_t registers_size_;
+  uint16_t ins_size_;
+  uint16_t outs_size_;
+  uint16_t tries_size_;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/code_item_accessors_test.cc b/runtime/code_item_accessors_test.cc
new file mode 100644
index 0000000..ef5d246
--- /dev/null
+++ b/runtime/code_item_accessors_test.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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 "code_item_accessors-inl.h"
+
+#include <memory>
+
+#include "common_runtime_test.h"
+#include "dex_file_loader.h"
+#include "mem_map.h"
+
+namespace art {
+
+class CodeItemAccessorsTest : public CommonRuntimeTest {};
+
+std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) {
+  std::string error_msg;
+  std::unique_ptr<MemMap> map(
+      MemMap::MapAnonymous(/*name*/ "map",
+                           /*addr*/ nullptr,
+                           /*byte_count*/ kPageSize,
+                           PROT_READ | PROT_WRITE,
+                           /*low_4gb*/ false,
+                           /*reuse*/ false,
+                           &error_msg));
+  CHECK(map != nullptr) << error_msg;
+  if (compact_dex) {
+    CompactDexFile::WriteMagic(map->Begin());
+    CompactDexFile::WriteCurrentVersion(map->Begin());
+  } else {
+    StandardDexFile::WriteMagic(map->Begin());
+    StandardDexFile::WriteCurrentVersion(map->Begin());
+  }
+  std::unique_ptr<const DexFile> dex(
+      DexFileLoader::Open("location",
+                          /*location_checksum*/ 123,
+                          std::move(map),
+                          /*verify*/false,
+                          /*verify_checksum*/false,
+                          &error_msg));
+  CHECK(dex != nullptr) << error_msg;
+  return dex;
+}
+
+TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) {
+  MemMap::Init();
+  std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false));
+  ASSERT_TRUE(standard_dex != nullptr);
+  std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true));
+  ASSERT_TRUE(compact_dex != nullptr);
+  static constexpr uint16_t kRegisterSize = 1;
+  static constexpr uint16_t kInsSize = 2;
+  static constexpr uint16_t kOutsSize = 3;
+  static constexpr uint16_t kTriesSize = 4;
+  // debug_info_off_ is not accessible from the helpers yet.
+  static constexpr size_t kInsnsSizeInCodeUnits = 5;
+
+  auto verify_code_item = [&](const DexFile* dex,
+                              const DexFile::CodeItem* item,
+                              const uint16_t* insns) {
+    CodeItemInstructionAccessor insns_accessor(dex, item);
+    EXPECT_TRUE(insns_accessor.HasCodeItem());
+    ASSERT_EQ(insns_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
+    EXPECT_EQ(insns_accessor.Insns(), insns);
+
+    CodeItemDataAccessor data_accessor(dex, item);
+    EXPECT_TRUE(data_accessor.HasCodeItem());
+    EXPECT_EQ(data_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
+    EXPECT_EQ(data_accessor.Insns(), insns);
+    EXPECT_EQ(data_accessor.RegistersSize(), kRegisterSize);
+    EXPECT_EQ(data_accessor.InsSize(), kInsSize);
+    EXPECT_EQ(data_accessor.OutsSize(), kOutsSize);
+    EXPECT_EQ(data_accessor.TriesSize(), kTriesSize);
+  };
+
+  uint8_t buffer1[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
+  CompactDexFile::CodeItem* dex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer1);
+  dex_code_item->registers_size_ = kRegisterSize;
+  dex_code_item->ins_size_ = kInsSize;
+  dex_code_item->outs_size_ = kOutsSize;
+  dex_code_item->tries_size_ = kTriesSize;
+  dex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
+  verify_code_item(compact_dex.get(), dex_code_item, dex_code_item->insns_);
+
+  uint8_t buffer2[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
+  CompactDexFile::CodeItem* cdex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer2);
+  cdex_code_item->registers_size_ = kRegisterSize;
+  cdex_code_item->ins_size_ = kInsSize;
+  cdex_code_item->outs_size_ = kOutsSize;
+  cdex_code_item->tries_size_ = kTriesSize;
+  cdex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
+  verify_code_item(compact_dex.get(), cdex_code_item, cdex_code_item->insns_);
+}
+
+}  // namespace art
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 5dfbd9b..58cd486 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -21,9 +21,11 @@
 #include "base/casts.h"
 #include "base/logging.h"
 #include "base/stringpiece.h"
+#include "cdex/compact_dex_file.h"
 #include "dex_file.h"
 #include "invoke_type.h"
 #include "leb128.h"
+#include "standard_dex_file.h"
 
 namespace art {
 
@@ -495,6 +497,16 @@
                                  context);
 }
 
+inline const CompactDexFile* DexFile::AsCompactDexFile() const {
+  DCHECK(IsCompactDexFile());
+  return down_cast<const CompactDexFile*>(this);
+}
+
+inline const StandardDexFile* DexFile::AsStandardDexFile() const {
+  DCHECK(IsStandardDexFile());
+  return down_cast<const StandardDexFile*>(this);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_DEX_FILE_INL_H_
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 974c7ac..7b0c46b 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -77,7 +77,8 @@
                  const std::string& location,
                  uint32_t location_checksum,
                  const OatDexFile* oat_dex_file,
-                 DexFileContainer* container)
+                 DexFileContainer* container,
+                 bool is_compact_dex)
     : begin_(base),
       size_(size),
       location_(location),
@@ -94,7 +95,8 @@
       call_site_ids_(nullptr),
       num_call_site_ids_(0),
       oat_dex_file_(oat_dex_file),
-      container_(container) {
+      container_(container),
+      is_compact_dex_(is_compact_dex) {
   CHECK(begin_ != nullptr) << GetLocation();
   CHECK_GT(size_, 0U) << GetLocation();
   // Check base (=header) alignment.
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 5c9b258..5c0093f 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -32,10 +32,12 @@
 
 namespace art {
 
+class CompactDexFile;
 enum InvokeType : uint32_t;
 class MemMap;
 class OatDexFile;
 class Signature;
+class StandardDexFile;
 class StringPiece;
 class ZipArchive;
 
@@ -993,13 +995,15 @@
   // Returns a human-readable form of the type at an index.
   std::string PrettyType(dex::TypeIndex type_idx) const;
 
-  // Helper functions.
-  virtual bool IsCompactDexFile() const {
-    return false;
+  // Not virtual for performance reasons.
+  ALWAYS_INLINE bool IsCompactDexFile() const {
+    return is_compact_dex_;
   }
-  virtual bool IsStandardDexFile() const {
-    return false;
+  ALWAYS_INLINE bool IsStandardDexFile() const {
+    return !is_compact_dex_;
   }
+  ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
+  ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
 
  protected:
   DexFile(const uint8_t* base,
@@ -1007,7 +1011,8 @@
           const std::string& location,
           uint32_t location_checksum,
           const OatDexFile* oat_dex_file,
-          DexFileContainer* container);
+          DexFileContainer* container,
+          bool is_compact_dex);
 
   // Top-level initializer that calls other Init methods.
   bool Init(std::string* error_msg);
@@ -1073,6 +1078,9 @@
   // Manages the underlying memory allocation.
   std::unique_ptr<DexFileContainer> container_;
 
+  // If the dex file is a compact dex file. If false then the dex file is a standard dex file.
+  const bool is_compact_dex_;
+
   friend class DexFileLoader;
   friend class DexFileVerifierTest;
   friend class OatWriter;
diff --git a/runtime/gc/allocator/dlmalloc.h b/runtime/gc/allocator/dlmalloc.h
index c07da5d..29b96ee 100644
--- a/runtime/gc/allocator/dlmalloc.h
+++ b/runtime/gc/allocator/dlmalloc.h
@@ -35,13 +35,6 @@
 #include "../../external/dlmalloc/malloc.h"
 #pragma GCC diagnostic pop
 
-#ifdef ART_TARGET_ANDROID
-// Define dlmalloc routines from bionic that cannot be included directly because of redefining
-// symbols from the include above.
-extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), void* arg);
-extern "C" int  dlmalloc_trim(size_t);
-#endif
-
 // Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
 // pages back to the kernel.
 extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 1344ca0..e54a017 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -44,8 +44,7 @@
   DCHECK(!method->IsNative());
 
   std::vector<uint32_t> entries;
-
-  for (const DexInstructionPcPair& inst : method->GetCodeItem()->Instructions()) {
+  for (const DexInstructionPcPair& inst : method->DexInstructions()) {
     switch (inst->Opcode()) {
       case Instruction::INVOKE_VIRTUAL:
       case Instruction::INVOKE_VIRTUAL_RANGE:
diff --git a/runtime/standard_dex_file.cc b/runtime/standard_dex_file.cc
index 36bb37a..4c1d308 100644
--- a/runtime/standard_dex_file.cc
+++ b/runtime/standard_dex_file.cc
@@ -31,6 +31,16 @@
   {'0', '3', '9', '\0'},
 };
 
+void StandardDexFile::WriteMagic(uint8_t* magic) {
+  std::copy_n(kDexMagic, kDexMagicSize, magic);
+}
+
+void StandardDexFile::WriteCurrentVersion(uint8_t* magic) {
+  std::copy_n(kDexMagicVersions[StandardDexFile::kDexVersionLen - 1],
+              kDexVersionLen,
+              magic + kDexMagicSize);
+}
+
 bool StandardDexFile::IsMagicValid(const uint8_t* magic) {
   return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
 }
diff --git a/runtime/standard_dex_file.h b/runtime/standard_dex_file.h
index 784ab31..5d53597 100644
--- a/runtime/standard_dex_file.h
+++ b/runtime/standard_dex_file.h
@@ -32,6 +32,18 @@
     // Same for now.
   };
 
+  struct CodeItem : public DexFile::CodeItem {
+   private:
+    // TODO: Insert standard dex specific fields here.
+    DISALLOW_COPY_AND_ASSIGN(CodeItem);
+  };
+
+  // Write the standard dex specific magic.
+  static void WriteMagic(uint8_t* magic);
+
+  // Write the current version, note that the input is the address of the magic.
+  static void WriteCurrentVersion(uint8_t* magic);
+
   static const uint8_t kDexMagic[kDexMagicSize];
   static constexpr size_t kNumDexVersions = 4;
   static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
@@ -44,10 +56,6 @@
   static bool IsVersionValid(const uint8_t* magic);
   virtual bool IsVersionValid() const OVERRIDE;
 
-  bool IsStandardDexFile() const OVERRIDE {
-    return true;
-  }
-
  private:
   StandardDexFile(const uint8_t* base,
                   size_t size,
@@ -55,7 +63,13 @@
                   uint32_t location_checksum,
                   const OatDexFile* oat_dex_file,
                   DexFileContainer* container)
-      : DexFile(base, size, location, location_checksum, oat_dex_file, container) {}
+      : DexFile(base,
+                size,
+                location,
+                location_checksum,
+                oat_dex_file,
+                container,
+                /*is_compact_dex*/ false) {}
 
   friend class DexFileLoader;
   friend class DexFileVerifierTest;