Add code item accessor helper classes

Add classes to abstract accesses to code item data. These classes
handle both standard dex and compact dex.

Added:
- CodeItemInstructionsAccessor to handle code item instructions.
- CodeItemDataAccessor to handle code item data excluding debug info.

Moved inline_method_analyzer to use the new classes to test the new
APIs.

Bug: 63756964
Test: test-art-host
Change-Id: I9926acb77b81fa64ed4a3b49b7bed1aab30a0f33
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/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 12b4d16..eb16e6e 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"
@@ -457,6 +458,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 8927481..df9b3aa 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"
@@ -700,6 +702,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/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;