Merge "ART: Simplify MethodHandle invocations"
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 37e6d42..0f29f29 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -33,13 +33,6 @@
 # rule name such as test-art-host-oat-optimizing-HelloWorld64.
 ART_TEST_KNOWN_BROKEN :=
 
-# List of run-tests to skip running in any configuration. This needs to be the full name of the
-# run-test such as '457-regs'.
-ART_TEST_RUN_TEST_SKIP ?=
-
-# Failing valgrind tests.
-# Note: *all* 64b tests involving the runtime do not work currently. b/15170219.
-
 # List of known failing tests that when executed won't cause test execution to not finish.
 # The test name must be the full rule name such as test-art-host-oat-optimizing-HelloWorld64.
 ART_TEST_KNOWN_FAILING :=
@@ -47,85 +40,9 @@
 # Keep going after encountering a test failure?
 ART_TEST_KEEP_GOING ?= true
 
-# Do you want all tests, even those that are time consuming?
-ART_TEST_FULL ?= false
-
 # Do you want run-test to be quieter? run-tests will only show output if they fail.
 ART_TEST_QUIET ?= true
 
-# Do you want interpreter tests run?
-ART_TEST_INTERPRETER ?= true
-ART_TEST_INTERPRETER_ACCESS_CHECKS ?= true
-
-# Do you want JIT tests run?
-ART_TEST_JIT ?= true
-
-# Do you want optimizing compiler tests run?
-ART_TEST_OPTIMIZING ?= true
-
-# Do you want to test the optimizing compiler with graph coloring register allocation?
-ART_TEST_OPTIMIZING_GRAPH_COLOR ?= $(ART_TEST_FULL)
-
-# Do you want to do run-tests with profiles?
-ART_TEST_SPEED_PROFILE ?= $(ART_TEST_FULL)
-
-# Do we want to test PIC-compiled tests ("apps")?
-ART_TEST_PIC_TEST ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests run?
-ART_TEST_TRACE ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests (streaming mode) run?
-ART_TEST_TRACE_STREAM ?= $(ART_TEST_FULL)
-
-# Do you want tests with GC verification enabled run?
-ART_TEST_GC_VERIFY ?= $(ART_TEST_FULL)
-
-# Do you want tests with the GC stress mode enabled run?
-ART_TEST_GC_STRESS ?= $(ART_TEST_FULL)
-
-# Do you want tests with the JNI forcecopy mode enabled run?
-ART_TEST_JNI_FORCECOPY ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled run?
-ART_TEST_RUN_TEST_RELOCATE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with prebuilding?
-ART_TEST_RUN_TEST_PREBUILD ?= true
-
-# Do you want run-tests with no prebuilding enabled run?
-ART_TEST_RUN_TEST_NO_PREBUILD ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with a pregenerated core.art?
-ART_TEST_RUN_TEST_IMAGE ?= true
-
-# Do you want run-tests without a pregenerated core.art?
-ART_TEST_RUN_TEST_NO_IMAGE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled but patchoat failing?
-ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests without a dex2oat?
-ART_TEST_RUN_TEST_NO_DEX2OAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with libartd.so?
-ART_TEST_RUN_TEST_DEBUG ?= true
-
-# Do you want run-tests with libart.so?
-ART_TEST_RUN_TEST_NDEBUG ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with the host/target's second arch?
-ART_TEST_RUN_TEST_2ND_ARCH ?= true
-
-# Do you want failed tests to have their artifacts cleaned up?
-ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
-
-# Do you want run-tests with the --debuggable flag
-ART_TEST_RUN_TEST_DEBUGGABLE ?= $(ART_TEST_FULL)
-
-# Do you want to test multi-part boot-image functionality?
-ART_TEST_RUN_TEST_MULTI_IMAGE ?= $(ART_TEST_FULL)
-
 # Define the command run on test failure. $(1) is the name of the test. Executed by the shell.
 # If the test was a top-level make target (e.g. `test-art-host-gtest-codegen_test64`), the command
 # fails with exit status 1 (returned by the last `grep` statement below).
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 7769aad..42d0ba5 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -146,13 +146,13 @@
   $(HOST_CORE_IMAGE_optimizing_32) \
   $(HOST_CORE_IMAGE_interpreter_64) \
   $(HOST_CORE_IMAGE_interpreter_32) \
-  $(HOST_OUT_EXECUTABLES)/patchoatd
+  patchoatd-host
 ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_optimizing_64) \
   $(TARGET_CORE_IMAGE_optimizing_32) \
   $(TARGET_CORE_IMAGE_interpreter_64) \
   $(TARGET_CORE_IMAGE_interpreter_32) \
-  $(TARGET_OUT_EXECUTABLES)/patchoatd
+  patchoatd-target
 
 ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -161,10 +161,10 @@
 
 ART_GTEST_dexoptanalyzer_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
-  $(HOST_OUT_EXECUTABLES)/dexoptanalyzerd
+  dexoptanalyzerd-host
 ART_GTEST_dexoptanalyzer_test_TARGET_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
-  dexoptanalyzerd
+  dexoptanalyzerd-target
 
 ART_GTEST_image_space_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -172,57 +172,59 @@
   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 ART_GTEST_dex2oat_test_HOST_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+  dex2oatd-host
 ART_GTEST_dex2oat_test_TARGET_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+  dex2oatd-target
 
 ART_GTEST_dex2oat_image_test_HOST_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+  dex2oatd-host
 ART_GTEST_dex2oat_image_test_TARGET_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+  dex2oatd-target
 
 # TODO: document why this is needed.
 ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
 
 # The dexdiag test requires the dexdiag utility.
-ART_GTEST_dexdiag_test_HOST_DEPS := \
-  $(HOST_OUT_EXECUTABLES)/dexdiag
-ART_GTEST_dexdiag_test_TARGET_DEPS := \
-  dexdiag
+ART_GTEST_dexdiag_test_HOST_DEPS := dexdiag-host
+ART_GTEST_dexdiag_test_TARGET_DEPS := dexdiag-target
 
 # The dexdump test requires an image and the dexdump utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexdump_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexdump2
+  dexdump2-host
 ART_GTEST_dexdump_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexdump2
+  dexdump2-target
 
 # The dexlayout test requires an image and the dexlayout utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexlayout_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexlayout \
-  $(HOST_OUT_EXECUTABLES)/dexdump2
+  dexlayoutd-host \
+  dexdump2-host
 ART_GTEST_dexlayout_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexlayout \
-  dexdump2
+  dexlayoutd-target \
+  dexdump2-target
 
 # The dexlist test requires an image and the dexlist utility.
 ART_GTEST_dexlist_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexlist
+  dexlist-host
 ART_GTEST_dexlist_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexlist
+  dexlist-target
 
 # The imgdiag test has dependencies on core.oat since it needs to load it during the test.
 # For the host, also add the installed tool (in the base size, that should suffice). For the
@@ -230,30 +232,28 @@
 ART_GTEST_imgdiag_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/imgdiagd
+  imgdiagd-host
 ART_GTEST_imgdiag_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  imgdiagd
+  imgdiagd-target
 
 # Oatdump test requires an image and oatfile to dump.
 ART_GTEST_oatdump_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/oatdumpd \
-  $(HOST_OUT_EXECUTABLES)/oatdumpds
+  oatdumpd-host \
+  oatdumpds-host
 ART_GTEST_oatdump_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  oatdump
+  oatdumpd-target
 ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS)
 ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS)
 
 # Profile assistant tests requires profman utility.
-ART_GTEST_profile_assistant_test_HOST_DEPS := \
-  $(HOST_OUT_EXECUTABLES)/profmand
-ART_GTEST_profile_assistant_test_TARGET_DEPS := \
-  profman
+ART_GTEST_profile_assistant_test_HOST_DEPS := profmand-host
+ART_GTEST_profile_assistant_test_TARGET_DEPS := profmand-target
 
 # The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 6637be2..979c4c4 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -91,19 +91,7 @@
       it.SkipAllFields();
 
       // Unquicken each method.
-      while (it.HasNextDirectMethod()) {
-        uint32_t method_idx = it.GetMemberIndex();
-        CompiledMethod* compiled_method =
-            compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
-        ArrayRef<const uint8_t> table;
-        if (compiled_method != nullptr) {
-          table = compiled_method->GetVmapTable();
-        }
-        optimizer::ArtDecompileDEX(
-            *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
-        it.Next();
-      }
-      while (it.HasNextVirtualMethod()) {
+      while (it.HasNextMethod()) {
         uint32_t method_idx = it.GetMemberIndex();
         CompiledMethod* compiled_method =
             compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
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/dex/verified_method.cc b/compiler/dex/verified_method.cc
index df75e07..524b0a6 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -20,6 +20,7 @@
 #include <memory>
 
 #include "base/logging.h"
+#include "code_item_accessors-inl.h"
 #include "dex_file.h"
 #include "dex_instruction-inl.h"
 #include "runtime.h"
@@ -64,7 +65,7 @@
   if (method_verifier->HasFailures()) {
     return;
   }
-  for (const DexInstructionPcPair& pair : method_verifier->CodeItem()->Instructions()) {
+  for (const DexInstructionPcPair& pair : method_verifier->CodeItem()) {
     const Instruction& inst = pair.Inst();
     const Instruction::Code code = inst.Opcode();
     if (code == Instruction::CHECK_CAST) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 32d0bbe..f4700d4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -762,31 +762,17 @@
         continue;
       }
 
-      // Direct methods.
-      int64_t previous_direct_method_idx = -1;
-      while (it.HasNextDirectMethod()) {
+      // Direct and virtual methods.
+      int64_t previous_method_idx = -1;
+      while (it.HasNextMethod()) {
         uint32_t method_idx = it.GetMemberIndex();
-        if (method_idx == previous_direct_method_idx) {
+        if (method_idx == previous_method_idx) {
           // smali can create dex files with two encoded_methods sharing the same method_idx
           // http://code.google.com/p/smali/issues/detail?id=119
           it.Next();
           continue;
         }
-        previous_direct_method_idx = method_idx;
-        ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
-        it.Next();
-      }
-      // Virtual methods.
-      int64_t previous_virtual_method_idx = -1;
-      while (it.HasNextVirtualMethod()) {
-        uint32_t method_idx = it.GetMemberIndex();
-        if (method_idx == previous_virtual_method_idx) {
-          // smali can create dex files with two encoded_methods sharing the same method_idx
-          // http://code.google.com/p/smali/issues/detail?id=119
-          it.Next();
-          continue;
-        }
-        previous_virtual_method_idx = method_idx;
+        previous_method_idx = method_idx;
         ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
         it.Next();
       }
@@ -1702,16 +1688,7 @@
         it.Next();
       }
       if (resolve_fields_and_methods) {
-        while (it.HasNextDirectMethod()) {
-          ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
-              it.GetMethodInvokeType(class_def));
-          if (method == nullptr) {
-            CheckAndClearResolveException(soa.Self());
-          }
-          it.Next();
-        }
-        while (it.HasNextVirtualMethod()) {
+        while (it.HasNextMethod()) {
           ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
               dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
               it.GetMethodInvokeType(class_def));
@@ -1820,12 +1797,7 @@
   ClassDataItemIterator it(dex_file, class_data);
   it.SkipAllFields();
 
-  while (it.HasNextDirectMethod()) {
-    verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
-    it.Next();
-  }
-
-  while (it.HasNextVirtualMethod()) {
+  while (it.HasNextMethod()) {
     verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
     it.Next();
   }
@@ -2752,17 +2724,17 @@
     bool compilation_enabled = driver->IsClassToCompile(
         dex_file.StringByTypeIdx(class_def.class_idx_));
 
-    // Compile direct methods
-    int64_t previous_direct_method_idx = -1;
-    while (it.HasNextDirectMethod()) {
+    // Compile direct and virtual methods.
+    int64_t previous_method_idx = -1;
+    while (it.HasNextMethod()) {
       uint32_t method_idx = it.GetMemberIndex();
-      if (method_idx == previous_direct_method_idx) {
+      if (method_idx == previous_method_idx) {
         // smali can create dex files with two encoded_methods sharing the same method_idx
         // http://code.google.com/p/smali/issues/detail?id=119
         it.Next();
         continue;
       }
-      previous_direct_method_idx = method_idx;
+      previous_method_idx = method_idx;
       CompileMethod(soa.Self(),
                     driver,
                     it.GetMethodCodeItem(),
@@ -2777,30 +2749,6 @@
                     dex_cache);
       it.Next();
     }
-    // Compile virtual methods
-    int64_t previous_virtual_method_idx = -1;
-    while (it.HasNextVirtualMethod()) {
-      uint32_t method_idx = it.GetMemberIndex();
-      if (method_idx == previous_virtual_method_idx) {
-        // smali can create dex files with two encoded_methods sharing the same method_idx
-        // http://code.google.com/p/smali/issues/detail?id=119
-        it.Next();
-        continue;
-      }
-      previous_virtual_method_idx = method_idx;
-      CompileMethod(soa.Self(),
-                    driver, it.GetMethodCodeItem(),
-                    it.GetMethodAccessFlags(),
-                    it.GetMethodInvokeType(class_def),
-                    class_def_index,
-                    method_idx,
-                    class_loader,
-                    dex_file,
-                    dex_to_dex_compilation_level,
-                    compilation_enabled,
-                    dex_cache);
-      it.Next();
-    }
     DCHECK(!it.HasNext());
   }
 
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 5c89869..0c82d60 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -80,6 +80,9 @@
 
 JitCompiler::JitCompiler() {
   compiler_options_.reset(new CompilerOptions());
+  // Special case max code units for inlining, whose default is "unset" (implictly
+  // meaning no limit). Do this before parsing the actuall passed options.
+  compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
   {
     std::string error_msg;
     if (!compiler_options_->ParseCompilerOptions(Runtime::Current()->GetCompilerOptions(),
@@ -95,10 +98,6 @@
   // Set debuggability based on the runtime value.
   compiler_options_->SetDebuggable(Runtime::Current()->IsJavaDebuggable());
 
-  // Special case max code units for inlining, whose default is "unset" (implictly
-  // meaning no limit).
-  compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
-
   const InstructionSet instruction_set = kRuntimeISA;
   for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) {
     VLOG(compiler) << "JIT compiler option " << option;
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index 595dd4d..2432f13 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -269,7 +269,9 @@
     // loop for synchronized blocks.
     if (ContainsElement(throwing_blocks_, block)) {
       // Try to find a TryItem covering the block.
-      const int32_t try_item_idx = DexFile::FindTryItem(code_item_, block->GetDexPc());
+      const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(code_item_, 0u),
+                                                        code_item_.tries_size_,
+                                                        block->GetDexPc());
       if (try_item_idx != -1) {
         // Block throwing and in a TryItem. Store the try block information.
         try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(code_item_, try_item_idx));
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f9f5a4d..ddec0cc 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2474,6 +2474,7 @@
             }
           }
       } else {
+        const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
         MipsLabel done;
         if (instr->IsShl()) {
           __ Sllv(dst_low, lhs_low, rhs_reg);
@@ -2483,9 +2484,14 @@
           __ Sllv(dst_high, lhs_high, rhs_reg);
           __ Or(dst_high, dst_high, TMP);
           __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
-          __ Beqz(TMP, &done);
-          __ Move(dst_high, dst_low);
-          __ Move(dst_low, ZERO);
+          if (isR6) {
+            __ Beqzc(TMP, &done, /* is_bare */ true);
+            __ Move(dst_high, dst_low);
+            __ Move(dst_low, ZERO);
+          } else {
+            __ Movn(dst_high, dst_low, TMP);
+            __ Movn(dst_low, ZERO, TMP);
+          }
         } else if (instr->IsShr()) {
           __ Srav(dst_high, lhs_high, rhs_reg);
           __ Nor(AT, ZERO, rhs_reg);
@@ -2494,9 +2500,15 @@
           __ Srlv(dst_low, lhs_low, rhs_reg);
           __ Or(dst_low, dst_low, TMP);
           __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
-          __ Beqz(TMP, &done);
-          __ Move(dst_low, dst_high);
-          __ Sra(dst_high, dst_high, 31);
+          if (isR6) {
+            __ Beqzc(TMP, &done, /* is_bare */ true);
+            __ Move(dst_low, dst_high);
+            __ Sra(dst_high, dst_high, 31);
+          } else {
+            __ Sra(AT, dst_high, 31);
+            __ Movn(dst_low, dst_high, TMP);
+            __ Movn(dst_high, AT, TMP);
+          }
         } else if (instr->IsUShr()) {
           __ Srlv(dst_high, lhs_high, rhs_reg);
           __ Nor(AT, ZERO, rhs_reg);
@@ -2505,10 +2517,15 @@
           __ Srlv(dst_low, lhs_low, rhs_reg);
           __ Or(dst_low, dst_low, TMP);
           __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
-          __ Beqz(TMP, &done);
-          __ Move(dst_low, dst_high);
-          __ Move(dst_high, ZERO);
-        } else {
+          if (isR6) {
+            __ Beqzc(TMP, &done, /* is_bare */ true);
+            __ Move(dst_low, dst_high);
+            __ Move(dst_high, ZERO);
+          } else {
+            __ Movn(dst_low, dst_high, TMP);
+            __ Movn(dst_high, ZERO, TMP);
+          }
+        } else {  // Rotate.
           __ Nor(AT, ZERO, rhs_reg);
           __ Srlv(TMP, lhs_low, rhs_reg);
           __ Sll(dst_low, lhs_high, 1);
@@ -2519,10 +2536,16 @@
           __ Sllv(dst_high, dst_high, AT);
           __ Or(dst_high, dst_high, TMP);
           __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
-          __ Beqz(TMP, &done);
-          __ Move(TMP, dst_high);
-          __ Move(dst_high, dst_low);
-          __ Move(dst_low, TMP);
+          if (isR6) {
+            __ Beqzc(TMP, &done, /* is_bare */ true);
+            __ Move(TMP, dst_high);
+            __ Move(dst_high, dst_low);
+            __ Move(dst_low, TMP);
+          } else {
+            __ Movn(AT, dst_high, TMP);
+            __ Movn(dst_high, dst_low, TMP);
+            __ Movn(dst_low, AT, TMP);
+          }
         }
         __ Bind(&done);
       }
diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index 999026c..aa8b5bb 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -32,8 +32,7 @@
         position_(pos),
         is_singleton_(true),
         is_singleton_and_not_returned_(true),
-        is_singleton_and_not_deopt_visible_(true),
-        has_index_aliasing_(false) {
+        is_singleton_and_not_deopt_visible_(true) {
     CalculateEscape(reference_,
                     nullptr,
                     &is_singleton_,
@@ -70,16 +69,6 @@
            (!is_singleton_and_not_returned_ || !is_singleton_and_not_deopt_visible_);
   }
 
-  bool HasIndexAliasing() {
-    return has_index_aliasing_;
-  }
-
-  void SetHasIndexAliasing(bool has_index_aliasing) {
-    // Only allow setting to true.
-    DCHECK(has_index_aliasing);
-    has_index_aliasing_ = has_index_aliasing;
-  }
-
  private:
   HInstruction* const reference_;
   const size_t position_;  // position in HeapLocationCollector's ref_info_array_.
@@ -90,9 +79,6 @@
   bool is_singleton_and_not_returned_;
   // Is singleton and not used as an environment local of HDeoptimize.
   bool is_singleton_and_not_deopt_visible_;
-  // Some heap locations with reference_ have array index aliasing,
-  // e.g. arr[i] and arr[j] may be the same location.
-  bool has_index_aliasing_;
 
   DISALLOW_COPY_AND_ASSIGN(ReferenceInfo);
 };
@@ -117,7 +103,8 @@
         index_(index),
         vector_length_(vector_length),
         declaring_class_def_index_(declaring_class_def_index),
-        value_killed_by_loop_side_effects_(true) {
+        value_killed_by_loop_side_effects_(true),
+        has_aliased_locations_(false) {
     DCHECK(ref_info != nullptr);
     DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
            (offset != kInvalidFieldOffset && index == nullptr));
@@ -151,6 +138,14 @@
     value_killed_by_loop_side_effects_ = val;
   }
 
+  bool HasAliasedLocations() const {
+    return has_aliased_locations_;
+  }
+
+  void SetHasAliasedLocations(bool val) {
+    has_aliased_locations_ = val;
+  }
+
  private:
   // Reference for instance/static field, array element or vector data.
   ReferenceInfo* const ref_info_;
@@ -173,6 +168,11 @@
   // value may be killed by loop side effects.
   bool value_killed_by_loop_side_effects_;
 
+  // Has aliased heap locations in the method, due to either the
+  // reference is aliased or the array element is aliased via different
+  // index names.
+  bool has_aliased_locations_;
+
   DISALLOW_COPY_AND_ASSIGN(HeapLocation);
 };
 
@@ -377,6 +377,7 @@
 
   // Compute if two locations may alias to each other.
   bool ComputeMayAlias(size_t index1, size_t index2) const {
+    DCHECK_NE(index1, index2);
     HeapLocation* loc1 = heap_locations_[index1];
     HeapLocation* loc2 = heap_locations_[index2];
     if (loc1->GetOffset() != loc2->GetOffset()) {
@@ -399,9 +400,9 @@
       if (!CanArrayElementsAlias(idx1, vector_length1, idx2, vector_length2)) {
         return false;
       }
-      ReferenceInfo* ref_info = loc1->GetReferenceInfo();
-      ref_info->SetHasIndexAliasing(true);
     }
+    loc1->SetHasAliasedLocations(true);
+    loc2->SetHasAliasedLocations(true);
     return true;
   }
 
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8678fab..605fdae 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -384,8 +384,10 @@
     if (Equal(heap_value, value)) {
       // Store into the heap location with the same value.
       same_value = true;
-    } else if (index != nullptr && ref_info->HasIndexAliasing()) {
-      // For array element, don't eliminate stores if the index can be aliased.
+    } else if (index != nullptr &&
+               heap_location_collector_.GetHeapLocation(idx)->HasAliasedLocations()) {
+      // For array element, don't eliminate stores if the location can be aliased
+      // (due to either ref or index aliasing).
     } else if (ref_info->IsSingleton()) {
       // Store into a field/element of a singleton. The value cannot be killed due to
       // aliasing/invocation. It can be redundant since future loads can
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index afca26d..fdada8f 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());
               }
             }
@@ -1244,7 +1244,7 @@
     ClassDataItemIterator it(*dex, dex->GetClassData(*class_def));
     it.SkipAllFields();
     std::set<size_t> code_item_offsets;
-    for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+    for (; it.HasNextMethod(); it.Next()) {
       const uint16_t method_idx = it.GetMemberIndex();
       const size_t code_item_offset = it.GetMethodCodeItemOffset();
       if (code_item_offsets.insert(code_item_offset).second) {
@@ -1356,7 +1356,7 @@
     // corresponding code item offsets to verify the layout.
     ClassDataItemIterator it(*dex_file, dex_file->GetClassData(*class_def));
     it.SkipAllFields();
-    for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+    for (; it.HasNextMethod(); it.Next()) {
       const size_t method_idx = it.GetMemberIndex();
       const size_t code_item_offset = it.GetMethodCodeItemOffset();
       const bool is_hot = ContainsElement(hot_methods, method_idx);
@@ -1382,7 +1382,7 @@
           // or this method is part of the last code item and the end is 4 byte aligned.
           ClassDataItemIterator it2(*dex_file, dex_file->GetClassData(*class_def));
           it2.SkipAllFields();
-          for (; it2.HasNextDirectMethod() || it2.HasNextVirtualMethod(); it2.Next()) {
+          for (; it2.HasNextMethod(); it2.Next()) {
               EXPECT_LE(it2.GetMethodCodeItemOffset(), code_item_offset);
           }
           uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d8671d2..1eec592 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -2126,20 +2126,14 @@
           ClassDataItemIterator it(*dex_file, class_data);
           it.SkipAllFields();
           size_t class_def_method_index = 0u;
-          while (it.HasNextDirectMethod()) {
+          while (it.HasNextMethod()) {
             if (!visitor->VisitMethod(class_def_method_index, it)) {
               return false;
             }
             ++class_def_method_index;
             it.Next();
           }
-          while (it.HasNextVirtualMethod()) {
-            if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
-              return false;
-            }
-            ++class_def_method_index;
-            it.Next();
-          }
+          DCHECK(!it.HasNext());
         }
       }
       if (UNLIKELY(!visitor->EndClass())) {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 4bfd91f..84ccaa0 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1391,18 +1391,12 @@
   }
   ClassDataItemIterator it(*dex_file, class_data);
   it.SkipAllFields();
-  while (it.HasNextDirectMethod()) {
+  while (it.HasNextMethod()) {
     dumpCfg(dex_file,
             it.GetMemberIndex(),
             it.GetMethodCodeItem());
     it.Next();
   }
-  while (it.HasNextVirtualMethod()) {
-    dumpCfg(dex_file,
-                it.GetMemberIndex(),
-                it.GetMethodCodeItem());
-    it.Next();
-  }
 }
 
 /*
diff --git a/dexdump/dexdump_cfg.cc b/dexdump/dexdump_cfg.cc
index 2831707..62c970d 100644
--- a/dexdump/dexdump_cfg.cc
+++ b/dexdump/dexdump_cfg.cc
@@ -377,7 +377,7 @@
   it.SkipAllFields();
 
   // Find method, and dump it.
-  while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+  while (it.HasNextMethod()) {
     uint32_t method_idx = it.GetMemberIndex();
     if (method_idx == dex_method_idx) {
       dumpMethodCFGImpl(dex_file, dex_method_idx, it.GetMethodCodeItem(), os);
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index fabe6e7..a02f75a 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -45,16 +45,34 @@
     shared_libs: ["libartd"],
 }
 
-art_cc_binary {
-    name: "dexlayout",
+cc_defaults {
+    name: "dexlayout-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
     srcs: ["dexlayout_main.cc"],
-    cflags: ["-Wall"],
+    shared_libs: [
+        "libbase",
+    ],
+}
+
+art_cc_binary {
+    name: "dexlayout",
+    defaults: ["dexlayout-defaults"],
     shared_libs: [
         "libart",
         "libart-dexlayout",
-        "libbase",
+    ],
+}
+
+art_cc_binary {
+    name: "dexlayoutd",
+    defaults: [
+        "art_debug_defaults",
+        "dexlayout-defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-dexlayout",
     ],
 }
 
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 0867305..c4f7acc 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -241,8 +241,8 @@
 
 class DexLayoutTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
-    CommonRuntimeTest::SetUp();
+  std::string GetDexLayoutPath() {
+    return GetTestAndroidRoot() + "/bin/dexlayoutd";
   }
 
   // Runs FullPlainOutput test.
@@ -255,18 +255,16 @@
 
     ScratchFile dexlayout_output;
     const std::string& dexlayout_filename = dexlayout_output.GetFilename();
-    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
 
     for (const std::string &dex_file : GetLibCoreDexFileNames()) {
       std::vector<std::string> dexdump_exec_argv =
           { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
-      std::vector<std::string> dexlayout_exec_argv =
-          { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
+      std::vector<std::string> dexlayout_args =
+          { "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
       if (!::art::Exec(dexdump_exec_argv, error_msg)) {
         return false;
       }
-      if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+      if (!DexLayoutExec(dexlayout_args, error_msg)) {
         return false;
       }
       std::vector<std::string> diff_exec_argv =
@@ -284,13 +282,11 @@
     const std::string& tmp_name = tmp_file.GetFilename();
     size_t tmp_last_slash = tmp_name.rfind('/');
     std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
-    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
 
     for (const std::string &dex_file : GetLibCoreDexFileNames()) {
-      std::vector<std::string> dexlayout_exec_argv =
-          { dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file };
-      if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+      std::vector<std::string> dexlayout_args =
+          { "-w", tmp_dir, "-o", tmp_name, dex_file };
+      if (!DexLayoutExec(dexlayout_args, error_msg)) {
         return false;
       }
       size_t dex_file_last_slash = dex_file.rfind('/');
@@ -418,12 +414,9 @@
     // WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
     std::string output_dex = tmp_dir + "classes.dex.new";
 
-    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
-    std::vector<std::string> dexlayout_exec_argv =
-        { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
-    if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+    std::vector<std::string> dexlayout_args =
+        { "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+    if (!DexLayoutExec(dexlayout_args, error_msg)) {
       return false;
     }
 
@@ -466,13 +459,10 @@
     std::string output_dex = tmp_dir + "classes.dex.new";
     std::string second_output_dex = tmp_dir + "classes.dex.new.new";
 
-    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
     // -v makes sure that the layout did not corrupt the dex file.
-    std::vector<std::string> dexlayout_exec_argv =
-        { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
-    if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+    std::vector<std::string> dexlayout_args =
+        { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+    if (!DexLayoutExec(dexlayout_args, error_msg)) {
       return false;
     }
 
@@ -482,9 +472,9 @@
 
     // -v makes sure that the layout did not corrupt the dex file.
     // -i since the checksum won't match from the first layout.
-    std::vector<std::string> second_dexlayout_exec_argv =
-        { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
-    if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
+    std::vector<std::string> second_dexlayout_args =
+        { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
+    if (!DexLayoutExec(second_dexlayout_args, error_msg)) {
       return false;
     }
 
@@ -516,12 +506,8 @@
     WriteFileBase64(filename, input_dex.c_str());
     std::string output_dex = tmp_dir + "classes.dex.new";
 
-    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
-    std::vector<std::string> dexlayout_exec_argv =
-        { dexlayout, "-w", tmp_dir, "-o", "/dev/null", input_dex };
-    if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+    std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
+    if (!DexLayoutExec(dexlayout_args, error_msg)) {
       return false;
     }
 
@@ -541,7 +527,7 @@
   bool DexLayoutExec(ScratchFile* dex_file,
                      const char* dex_filename,
                      ScratchFile* profile_file,
-                     std::vector<std::string>& dexlayout_exec_argv) {
+                     const std::vector<std::string>& dexlayout_args) {
     if (dex_filename != nullptr) {
       WriteBase64ToFile(dex_filename, dex_file->GetFile());
       EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
@@ -549,14 +535,27 @@
     if (profile_file != nullptr) {
       CreateProfile(dex_file->GetFilename(), profile_file->GetFilename(), dex_file->GetFilename());
     }
+
     std::string error_msg;
-    const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg);
+    const bool result = DexLayoutExec(dexlayout_args, &error_msg);
     if (!result) {
       LOG(ERROR) << "Error: " << error_msg;
       return false;
     }
     return true;
   }
+
+  bool DexLayoutExec(const std::vector<std::string>& dexlayout_args, std::string* error_msg) {
+    std::vector<std::string> argv;
+
+    std::string dexlayout = GetDexLayoutPath();
+    CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+    argv.push_back(dexlayout);
+
+    argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end());
+
+    return ::art::Exec(argv, error_msg);
+  }
 };
 
 
@@ -614,89 +613,72 @@
 
 TEST_F(DexLayoutTest, DuplicateOffset) {
   ScratchFile temp_dex;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args =
+      { "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDexFileDuplicateOffset,
                             nullptr /* profile_file */,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, NullSetRefListElement) {
   ScratchFile temp_dex;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kNullSetRefListElementInputDex,
                             nullptr /* profile_file */,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, MultiClassData) {
   ScratchFile temp_dex;
   ScratchFile temp_profile;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args =
+      { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kMultiClassDataInputDex,
                             &temp_profile,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, UnalignedCodeInfo) {
   ScratchFile temp_dex;
   ScratchFile temp_profile;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args =
+      { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kUnalignedCodeInfoInputDex,
                             &temp_profile,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, ClassDataBeforeCode) {
   ScratchFile temp_dex;
   ScratchFile temp_profile;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args =
+      { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kClassDataBeforeCodeInputDex,
                             &temp_profile,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, UnknownTypeDebugInfo) {
   ScratchFile temp_dex;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kUnknownTypeDebugInfoInputDex,
                             nullptr /* profile_file */,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 TEST_F(DexLayoutTest, DuplicateCodeItem) {
   ScratchFile temp_dex;
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDuplicateCodeItemInputDex,
                             nullptr /* profile_file */,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 // Test that instructions that go past the end of the code items don't cause crashes.
@@ -713,7 +695,7 @@
       }
       ClassDataItemIterator it(*dex, data);
       it.SkipAllFields();
-      while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+      while (it.HasNextMethod()) {
         DexFile::CodeItem* item = const_cast<DexFile::CodeItem*>(it.GetMethodCodeItem());
         if (item != nullptr) {
           IterationRange<DexInstructionIterator> instructions = item->Instructions();
@@ -743,14 +725,11 @@
     CHECK(mutated_successfully)
         << "Failed to find candidate code item with only one code unit in last instruction.";
   });
-  std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
-  EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-  std::vector<std::string> dexlayout_exec_argv =
-      { dexlayout, "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+  std::vector<std::string> dexlayout_args = { "-i", "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             /*dex_filename*/ nullptr,
                             nullptr /* profile_file */,
-                            dexlayout_exec_argv));
+                            dexlayout_args));
 }
 
 }  // namespace art
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index c8bc132..e3ca59c 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -151,16 +151,8 @@
   if (pEncodedData != nullptr) {
     ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
     pClassData.SkipAllFields();
-    // Direct methods.
-    for (; pClassData.HasNextDirectMethod(); pClassData.Next()) {
-      dumpMethod(pDexFile, fileName,
-                 pClassData.GetMemberIndex(),
-                 pClassData.GetRawMemberAccessFlags(),
-                 pClassData.GetMethodCodeItem(),
-                 pClassData.GetMethodCodeItemOffset());
-    }
-    // Virtual methods.
-    for (; pClassData.HasNextVirtualMethod(); pClassData.Next()) {
+    // Direct and virtual methods.
+    for (; pClassData.HasNextMethod(); pClassData.Next()) {
       dumpMethod(pDexFile, fileName,
                  pClassData.GetMemberIndex(),
                  pClassData.GetRawMemberAccessFlags(),
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b20fa90..cd2e894 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -36,6 +36,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "class_linker.h"
+#include "code_item_accessors-inl.h"
 #include "compiled_method.h"
 #include "debug/elf_debug_writer.h"
 #include "debug/method_debug_info.h"
@@ -274,7 +275,7 @@
     ClassDataItemIterator it(dex_file, class_data);
     uint32_t class_method_idx = 0;
     it.SkipAllFields();
-    for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+    for (; it.HasNextMethod(); it.Next()) {
       WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
                     dex_file,
                     class_def_index,
@@ -893,11 +894,7 @@
           ClassDataItemIterator it(*dex_file, class_data);
           it.SkipAllFields();
           uint32_t class_method_index = 0;
-          while (it.HasNextDirectMethod()) {
-            AddOffsets(oat_class.GetOatMethod(class_method_index++));
-            it.Next();
-          }
-          while (it.HasNextVirtualMethod()) {
+          while (it.HasNextMethod()) {
             AddOffsets(oat_class.GetOatMethod(class_method_index++));
             it.Next();
           }
@@ -979,11 +976,7 @@
       }
       ClassDataItemIterator it(dex_file, class_data);
       it.SkipAllFields();
-      while (it.HasNextDirectMethod()) {
-        WalkCodeItem(dex_file, it.GetMethodCodeItem());
-        it.Next();
-      }
-      while (it.HasNextVirtualMethod()) {
+      while (it.HasNextMethod()) {
         WalkCodeItem(dex_file, it.GetMethodCodeItem());
         it.Next();
       }
@@ -994,14 +987,15 @@
       if (code_item == nullptr) {
         return;
       }
+      CodeItemInstructionAccessor instructions(&dex_file, code_item);
 
-      const uint16_t* code_ptr = code_item->insns_;
       // If we inserted a new dex code item pointer, add to total code bytes.
+      const uint16_t* code_ptr = instructions.Insns();
       if (dex_code_item_ptrs_.insert(code_ptr).second) {
-        dex_code_bytes_ += code_item->insns_size_in_code_units_ * sizeof(code_ptr[0]);
+        dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]);
       }
 
-      for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+      for (const DexInstructionPcPair& inst : instructions) {
         switch (inst->Opcode()) {
           case Instruction::CONST_STRING: {
             const dex::StringIndex string_index(inst->VRegB_21c());
@@ -1227,20 +1221,7 @@
     ClassDataItemIterator it(dex_file, class_data);
     it.SkipAllFields();
     uint32_t class_method_index = 0;
-    while (it.HasNextDirectMethod()) {
-      if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
-                         it.GetMemberIndex(), it.GetMethodCodeItem(),
-                         it.GetRawMemberAccessFlags(), &addr_found)) {
-        success = false;
-      }
-      if (addr_found) {
-        *stop_analysis = true;
-        return success;
-      }
-      class_method_index++;
-      it.Next();
-    }
-    while (it.HasNextVirtualMethod()) {
+    while (it.HasNextMethod()) {
       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
                          it.GetMemberIndex(), it.GetMethodCodeItem(),
                          it.GetRawMemberAccessFlags(), &addr_found)) {
@@ -1266,11 +1247,17 @@
   bool DumpOatMethod(VariableIndentationOutputStream* vios,
                      const DexFile::ClassDef& class_def,
                      uint32_t class_method_index,
-                     const OatFile::OatClass& oat_class, const DexFile& dex_file,
-                     uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
-                     uint32_t method_access_flags, bool* addr_found) {
+                     const OatFile::OatClass& oat_class,
+                     const DexFile& dex_file,
+                     uint32_t dex_method_idx,
+                     const DexFile::CodeItem* code_item,
+                     uint32_t method_access_flags,
+                     bool* addr_found) {
     bool success = true;
 
+    CodeItemDataAccessor code_item_accessor(CodeItemDataAccessor::CreateNullable(&dex_file,
+                                                                                 code_item));
+
     // TODO: Support regex
     std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
     if (method_name.find(options_.method_filter_) == std::string::npos) {
@@ -1281,7 +1268,9 @@
     vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
                                    class_method_index, pretty_method.c_str(),
                                    dex_method_idx);
-    if (options_.list_methods_) return success;
+    if (options_.list_methods_) {
+      return success;
+    }
 
     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
@@ -1302,7 +1291,12 @@
     {
       vios->Stream() << "DEX CODE:\n";
       ScopedIndentation indent2(vios);
-      DumpDexCode(vios->Stream(), dex_file, code_item);
+      if (code_item_accessor.HasCodeItem()) {
+        for (const DexInstructionPcPair& inst : code_item_accessor) {
+          vios->Stream() << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
+                         << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
+        }
+      }
     }
 
     std::unique_ptr<StackHandleScope<1>> hs;
@@ -1373,7 +1367,7 @@
       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
 
       size_t vmap_table_offset_limit =
-          (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
+          (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor))
               ? oat_file_.GetVdexFile()->Size()
               : method_header->GetCode() - oat_file_.Begin();
       if (vmap_table_offset >= vmap_table_offset_limit) {
@@ -1385,7 +1379,7 @@
                                        oat_method.GetVmapTableOffsetOffset());
         success = false;
       } else if (options_.dump_vmap_) {
-        DumpVmapData(vios, oat_method, code_item);
+        DumpVmapData(vios, oat_method, code_item_accessor);
       }
     }
     {
@@ -1406,7 +1400,7 @@
       // after it is dumped, but useful for understanding quick
       // code, so dumped here.
       ScopedIndentation indent2(vios);
-      DumpVregLocations(vios->Stream(), oat_method, code_item);
+      DumpVregLocations(vios->Stream(), oat_method, code_item_accessor);
     }
     {
       vios->Stream() << "CODE: ";
@@ -1448,7 +1442,7 @@
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
             }
           }
         } else if (code_size > kMaxCodeSize) {
@@ -1461,11 +1455,11 @@
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
             }
           }
         } else if (options_.disassemble_code_) {
-          DumpCode(vios, oat_method, code_item, !success, 0);
+          DumpCode(vios, oat_method, code_item_accessor, !success, 0);
         }
       }
     }
@@ -1499,18 +1493,18 @@
   // Display data stored at the the vmap offset of an oat method.
   void DumpVmapData(VariableIndentationOutputStream* vios,
                     const OatFile::OatMethod& oat_method,
-                    const DexFile::CodeItem* code_item) {
-    if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+                    const CodeItemDataAccessor& code_item_accessor) {
+    if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item_accessor)) {
       // The optimizing compiler outputs its CodeInfo data in the vmap table.
       const void* raw_code_info = oat_method.GetVmapTable();
       if (raw_code_info != nullptr) {
         CodeInfo code_info(raw_code_info);
-        DCHECK(code_item != nullptr);
+        DCHECK(code_item_accessor.HasCodeItem());
         ScopedIndentation indent1(vios);
         MethodInfo method_info = oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo();
-        DumpCodeInfo(vios, code_info, oat_method, *code_item, method_info);
+        DumpCodeInfo(vios, code_info, oat_method, code_item_accessor, method_info);
       }
-    } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
+    } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)) {
       // We don't encode the size in the table, so just emit that we have quickened
       // information.
       ScopedIndentation indent(vios);
@@ -1524,11 +1518,11 @@
   void DumpCodeInfo(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
                     const OatFile::OatMethod& oat_method,
-                    const DexFile::CodeItem& code_item,
+                    const CodeItemDataAccessor& code_item_accessor,
                     const MethodInfo& method_info) {
     code_info.Dump(vios,
                    oat_method.GetCodeOffset(),
-                   code_item.registers_size_,
+                   code_item_accessor.RegistersSize(),
                    options_.dump_code_info_stack_maps_,
                    instruction_set_,
                    method_info);
@@ -1539,7 +1533,7 @@
     return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t);
   }
 
-  static uint32_t GetVRegOffsetFromQuickCode(const DexFile::CodeItem* code_item,
+  static uint32_t GetVRegOffsetFromQuickCode(const CodeItemDataAccessor& code_item_accessor,
                                              uint32_t core_spills,
                                              uint32_t fp_spills,
                                              size_t frame_size,
@@ -1557,8 +1551,8 @@
     int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
         + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
         + sizeof(uint32_t);  // Filler.
-    int num_regs = code_item->registers_size_ - code_item->ins_size_;
-    int temp_threshold = code_item->registers_size_;
+    int num_regs = code_item_accessor.RegistersSize() - code_item_accessor.InsSize();
+    int temp_threshold = code_item_accessor.RegistersSize();
     const int max_num_special_temps = 1;
     if (reg == temp_threshold) {
       // The current method pointer corresponds to special location on stack.
@@ -1568,7 +1562,7 @@
        * Special temporaries may have custom locations and the logic above deals with that.
        * However, non-special temporaries are placed relative to the outs.
        */
-      int temps_start = code_item->outs_size_ * sizeof(uint32_t)
+      int temps_start = code_item_accessor.OutsSize() * sizeof(uint32_t)
           + static_cast<size_t>(pointer_size) /* art method */;
       int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t);
       return temps_start + relative_offset;
@@ -1583,12 +1577,12 @@
   }
 
   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
-                         const DexFile::CodeItem* code_item) {
-    if (code_item != nullptr) {
-      size_t num_locals_ins = code_item->registers_size_;
-      size_t num_ins = code_item->ins_size_;
+                         const CodeItemDataAccessor& code_item_accessor) {
+    if (code_item_accessor.HasCodeItem()) {
+      size_t num_locals_ins = code_item_accessor.RegistersSize();
+      size_t num_ins = code_item_accessor.InsSize();
       size_t num_locals = num_locals_ins - num_ins;
-      size_t num_outs = code_item->outs_size_;
+      size_t num_outs = code_item_accessor.OutsSize();
 
       os << "vr_stack_locations:";
       for (size_t reg = 0; reg <= num_locals_ins; reg++) {
@@ -1601,7 +1595,7 @@
           os << "\n\tlocals:";
         }
 
-        uint32_t offset = GetVRegOffsetFromQuickCode(code_item,
+        uint32_t offset = GetVRegOffsetFromQuickCode(code_item_accessor,
                                                      oat_method.GetCoreSpillMask(),
                                                      oat_method.GetFpSpillMask(),
                                                      oat_method.GetFrameSizeInBytes(),
@@ -1623,37 +1617,30 @@
     }
   }
 
-  void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
-    if (code_item != nullptr) {
-      for (const DexInstructionPcPair& inst : code_item->Instructions()) {
-        os << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
-           << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
-      }
-    }
-  }
-
   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   // the optimizing compiler?
-  static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
-                                                    const DexFile::CodeItem* code_item) {
+  static bool IsMethodGeneratedByOptimizingCompiler(
+      const OatFile::OatMethod& oat_method,
+      const CodeItemDataAccessor& code_item_accessor) {
     // If the native GC map is null and the Dex `code_item` is not
     // null, then this method has been compiled with the optimizing
     // compiler.
     return oat_method.GetQuickCode() != nullptr &&
            oat_method.GetVmapTable() != nullptr &&
-           code_item != nullptr;
+           code_item_accessor.HasCodeItem();
   }
 
   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   // the dextodex compiler?
-  static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
-                                                  const DexFile::CodeItem* code_item) {
+  static bool IsMethodGeneratedByDexToDexCompiler(
+      const OatFile::OatMethod& oat_method,
+      const CodeItemDataAccessor& code_item_accessor) {
     // If the quick code is null, the Dex `code_item` is not
     // null, and the vmap table is not null, then this method has been compiled
     // with the dextodex compiler.
     return oat_method.GetQuickCode() == nullptr &&
            oat_method.GetVmapTable() != nullptr &&
-           code_item != nullptr;
+           code_item_accessor.HasCodeItem();
   }
 
   verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
@@ -1770,7 +1757,8 @@
   };
 
   void DumpCode(VariableIndentationOutputStream* vios,
-                const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
+                const OatFile::OatMethod& oat_method,
+                const CodeItemDataAccessor& code_item_accessor,
                 bool bad_input, size_t code_size) {
     const void* quick_code = oat_method.GetQuickCode();
 
@@ -1780,7 +1768,8 @@
     if (code_size == 0 || quick_code == nullptr) {
       vios->Stream() << "NO CODE!\n";
       return;
-    } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+    } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method,
+                                                                   code_item_accessor)) {
       // The optimizing compiler outputs its CodeInfo data in the vmap table.
       StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
       MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo());
@@ -1835,7 +1824,8 @@
                          kBitsPerByte * location_catalog_bytes);
           // Dex register bytes.
           const size_t dex_register_bytes =
-              helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_);
+              helper.GetCodeInfo().GetDexRegisterMapsSize(encoding,
+                                                          code_item_accessor.RegistersSize());
           stats_.AddBits(
               Stats::kByteKindCodeInfoDexRegisterMap,
               kBitsPerByte * dex_register_bytes);
@@ -1874,7 +1864,7 @@
                          helper.GetEncoding(),
                          method_info,
                          oat_method.GetCodeOffset(),
-                         code_item->registers_size_,
+                         code_item_accessor.RegistersSize(),
                          instruction_set_);
           do {
             helper.Next();
@@ -2502,8 +2492,8 @@
         }
       }
     } else {
-      const DexFile::CodeItem* code_item = method->GetCodeItem();
-      size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
+      CodeItemDataAccessor code_item_accessor(method);
+      size_t dex_instruction_bytes = code_item_accessor.InsnsSizeInCodeUnits() * 2;
       stats_.dex_instruction_bytes += dex_instruction_bytes;
 
       bool first_occurrence;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index dcc237d..5b125f6 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -610,7 +610,7 @@
   // Check each of the methods. NB we don't need to specifically check for removals since the 2 dex
   // files have the same number of methods, which means there must be an equal amount of additions
   // and removals.
-  for (; new_iter.HasNextVirtualMethod() || new_iter.HasNextDirectMethod(); new_iter.Next()) {
+  for (; new_iter.HasNextMethod(); new_iter.Next()) {
     // Get the data on the method we are searching for
     const art::DexFile::MethodId& new_method_id = dex_file_->GetMethodId(new_iter.GetMemberIndex());
     const char* new_method_name = dex_file_->GetMethodName(new_method_id);
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 6d075a6..b7b81ce 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -47,6 +47,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "nativehelper/scoped_local_ref.h"
+#include "nativehelper/scoped_utf_chars.h"
 #include "obj_ptr.h"
 #include "runtime.h"
 #include "runtime_callbacks.h"
@@ -701,6 +702,7 @@
   JavaVM* java_vm;
   jvmtiEnv* jvmti_env;
   jint priority;
+  std::string name;
 };
 
 static void* AgentCallback(void* arg) {
@@ -708,13 +710,13 @@
   CHECK(data->thread != nullptr);
 
   // We already have a peer. So call our special Attach function.
-  art::Thread* self = art::Thread::Attach("JVMTI Agent thread", true, data->thread);
+  art::Thread* self = art::Thread::Attach(data->name.c_str(), true, data->thread);
   CHECK(self != nullptr) << "threads_being_born_ should have ensured thread could be attached.";
   // The name in Attach() is only for logging. Set the thread name. This is important so
   // that the thread is no longer seen as starting up.
   {
     art::ScopedObjectAccess soa(self);
-    self->SetThreadName("JVMTI Agent thread");
+    self->SetThreadName(data->name.c_str());
   }
 
   // Release the peer.
@@ -781,6 +783,16 @@
   data->java_vm = art::Runtime::Current()->GetJavaVM();
   data->jvmti_env = jvmti_env;
   data->priority = priority;
+  ScopedLocalRef<jstring> s(
+      env,
+      reinterpret_cast<jstring>(
+          env->GetObjectField(thread, art::WellKnownClasses::java_lang_Thread_name)));
+  if (s == nullptr) {
+    data->name = "JVMTI Agent Thread";
+  } else {
+    ScopedUtfChars name(env, s.get());
+    data->name = name.c_str();
+  }
 
   pthread_t pthread;
   int pthread_create_result = pthread_create(&pthread,
diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc
index e5645d3..48b87c9 100644
--- a/profman/boot_image_profile.cc
+++ b/profman/boot_image_profile.cc
@@ -90,7 +90,7 @@
           it.Next();
         }
         it.SkipInstanceFields();
-        while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+        while (it.HasNextMethod()) {
           const uint32_t flags = it.GetMethodAccessFlags();
           if ((flags & kAccNative) != 0) {
             // Native method will get dirtied.
diff --git a/profman/profman.cc b/profman/profman.cc
index 1c50645..31d28e4 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -810,7 +810,7 @@
         if (class_data != nullptr) {
           ClassDataItemIterator it(*dex_file, class_data);
           it.SkipAllFields();
-          while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+          while (it.HasNextMethod()) {
             if (it.GetMethodCodeItemOffset() != 0) {
               // Add all of the methods that have code to the profile.
               const uint32_t method_idx = it.GetMemberIndex();
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/class_loader_context.cc b/runtime/class_loader_context.cc
index 38f59ef..54e7558 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -16,9 +16,6 @@
 
 #include "class_loader_context.h"
 
-#include <stdlib.h>
-
-#include "android-base/file.h"
 #include "art_field-inl.h"
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
@@ -210,19 +207,9 @@
     size_t opened_dex_files_index = info.opened_dex_files.size();
     for (const std::string& cp_elem : info.classpath) {
       // If path is relative, append it to the provided base directory.
-      std::string raw_location = cp_elem;
-      if (raw_location[0] != '/' && !classpath_dir.empty()) {
-        raw_location = classpath_dir + '/' + raw_location;
-      }
-
-      std::string location;  // the real location of the class path element.
-
-      if (!android::base::Realpath(raw_location, &location)) {
-        // If we can't get the realpath of the location there might be something wrong with the
-        // classpath (maybe the file was deleted).
-        // Do not continue in this case and return false.
-        PLOG(WARNING) << "Could not get the realpath of dex location " << raw_location;
-        return false;
+      std::string location = cp_elem;
+      if (location[0] != '/' && !classpath_dir.empty()) {
+        location = classpath_dir + (classpath_dir.back() == '/' ? "" : "/") + location;
       }
 
       std::string error_msg;
@@ -728,15 +715,20 @@
         dex_name = info.classpath[k];
         expected_dex_name = OatFile::ResolveRelativeEncodedDexLocation(
             info.classpath[k].c_str(), expected_info.classpath[k]);
-      } else {
+      } else if (is_expected_dex_name_absolute) {
         // The runtime name is relative but the compiled name is absolute.
         // There is no expected use case that would end up here as dex files are always loaded
         // with their absolute location. However, be tolerant and do the best effort (in case
         // there are unexpected new use case...).
-        DCHECK(is_expected_dex_name_absolute);
         dex_name = OatFile::ResolveRelativeEncodedDexLocation(
             expected_info.classpath[k].c_str(), info.classpath[k]);
         expected_dex_name = expected_info.classpath[k];
+      } else {
+        // Both locations are relative. In this case there's not much we can be sure about
+        // except that the names are the same. The checksum will ensure that the files are
+        // are same. This should not happen outside testing and manual invocations.
+        dex_name = info.classpath[k];
+        expected_dex_name = expected_info.classpath[k];
       }
 
       // Compare the locations.
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index be6acde..fc3446c 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -17,17 +17,13 @@
 #include "class_loader_context.h"
 
 #include <gtest/gtest.h>
-#include <stdlib.h>
 
 #include "android-base/strings.h"
-
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
-#include "class_loader_context.h"
 #include "class_linker.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "dex2oat_environment_test.h"
 #include "handle_scope-inl.h"
 #include "mirror/class.h"
 #include "mirror/class_loader.h"
@@ -84,6 +80,10 @@
     kEndsWith
   };
 
+  static bool IsAbsoluteLocation(const std::string& location) {
+    return !location.empty() && location[0] == '/';
+  }
+
   void VerifyOpenDexFiles(
       ClassLoaderContext* context,
       size_t index,
@@ -100,17 +100,22 @@
             info.opened_dex_files[cur_open_dex_index++];
       std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k];
 
-      std::string expected_location =
-          DexFileLoader::GetBaseLocation(expected_dex_file->GetLocation());
-      UniqueCPtr<const char[]> expected_real_location(
-          realpath(expected_location.c_str(), nullptr));
-      ASSERT_TRUE(expected_real_location != nullptr) << expected_location;
-      expected_location.assign(expected_real_location.get());
-      expected_location += DexFileLoader::GetMultiDexSuffix(expected_dex_file->GetLocation());
+      std::string expected_location = expected_dex_file->GetLocation();
 
-      ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
+      const std::string& opened_location = opened_dex_file->GetLocation();
+      if (!IsAbsoluteLocation(opened_location)) {
+        // If the opened location is relative (it was open from a relative path without a
+        // classpath_dir) it might not match the expected location which is absolute in tests).
+        // So we compare the endings (the checksum will validate it's actually the same file).
+        ASSERT_EQ(0, expected_location.compare(
+            expected_location.length() - opened_location.length(),
+            opened_location.length(),
+            opened_location));
+      } else {
+        ASSERT_EQ(expected_location, opened_location);
+      }
       ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
-      ASSERT_EQ(info.classpath[k], opened_dex_file->GetLocation());
+      ASSERT_EQ(info.classpath[k], opened_location);
     }
   }
 
@@ -252,6 +257,7 @@
   std::string myclass_dex_name = GetTestDexFileName("MyClass");
   std::string dex_name = GetTestDexFileName("Main");
 
+
   std::unique_ptr<ClassLoaderContext> context =
       ClassLoaderContext::Create(
           "PCL[" + multidex_name + ":" + myclass_dex_name + "];" +
@@ -272,42 +278,6 @@
   VerifyOpenDexFiles(context.get(), 1, &all_dex_files1);
 }
 
-class ScratchSymLink {
- public:
-  explicit ScratchSymLink(const std::string& file) {
-    // Use a temporary scratch file to get a unique name for the link.
-    ScratchFile scratchFile;
-    scratch_link_name_ = scratchFile.GetFilename() + ".link.jar";
-    CHECK_EQ(0, symlink(file.c_str(), scratch_link_name_.c_str()));
-  }
-
-  ~ScratchSymLink() {
-    CHECK_EQ(0, unlink(scratch_link_name_.c_str()));
-  }
-
-  const std::string& GetFilename() { return scratch_link_name_; }
-
- private:
-  std::string scratch_link_name_;
-};
-
-TEST_F(ClassLoaderContextTest, OpenValidDexFilesSymLink) {
-  std::string myclass_dex_name = GetTestDexFileName("MyClass");
-  // Now replace the dex location with a symlink.
-  ScratchSymLink link(myclass_dex_name);
-
-  std::unique_ptr<ClassLoaderContext> context =
-      ClassLoaderContext::Create("PCL[" + link.GetFilename() + "]");
-
-  ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ ""));
-
-  VerifyContextSize(context.get(), 1);
-
-  std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
-
-  VerifyOpenDexFiles(context.get(), 0, &myclass_dex_files);
-}
-
 static std::string CreateRelativeString(const std::string& in, const char* cwd) {
   int cwd_len = strlen(cwd);
   if (!android::base::StartsWith(in, cwd) || (cwd_len < 1)) {
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
new file mode 100644
index 0000000..d04849d
--- /dev/null
+++ b/runtime/code_item_accessors-inl.h
@@ -0,0 +1,155 @@
+/*
+ * 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 "dex_file-inl.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(
+    const DexFile* dex_file,
+    const DexFile::CodeItem* code_item) {
+  CodeItemDataAccessor ret;
+  if (code_item != nullptr) {
+    ret.Init(dex_file, code_item);
+  } else {
+    DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
+  }
+  return ret;
+}
+
+inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
+  DCHECK(method != nullptr);
+  return CreateNullable(method->GetDexFile(), method->GetCodeItem());
+}
+
+inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
+  const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
+  return {
+    try_items,
+    try_items + TriesSize() };
+}
+
+inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
+  return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
+}
+
+inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
+  IterationRange<const DexFile::TryItem*> try_items(TryItems());
+  int32_t index = DexFile::FindTryItem(try_items.begin(),
+                                       try_items.end() - try_items.begin(),
+                                       try_dex_pc);
+  return index != -1 ? &try_items.begin()[index] : nullptr;
+}
+
+}  // 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..aa1305a
--- /dev/null
+++ b/runtime/code_item_accessors.h
@@ -0,0 +1,137 @@
+/*
+ * 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 the instruction for a dex pc.
+  const Instruction& InstructionAt(uint32_t dex_pc) const {
+    return *Instruction::At(insns_ + dex_pc);
+  }
+
+  // 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_;
+  }
+
+  IterationRange<const DexFile::TryItem*> TryItems() const;
+
+  const uint8_t* GetCatchHandlerData(size_t offset = 0) const;
+
+  const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
+
+  // CreateNullable allows ArtMethods that have a null code item.
+  ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(
+      const DexFile* dex_file,
+      const DexFile::CodeItem* code_item);
+
+ 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..c926a0d 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 {
 
@@ -133,9 +135,13 @@
 }
 
 inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) {
-  const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_];
+  return GetTryItems(code_item.Instructions().end(), offset);
+}
+
+inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
+                                                    uint32_t offset) {
   return reinterpret_cast<const TryItem*>
-      (RoundUp(reinterpret_cast<uintptr_t>(insns_end_), 4)) + offset;
+      (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), 4)) + offset;
 }
 
 static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
@@ -495,6 +501,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..af79207 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.
@@ -484,20 +486,18 @@
   return Signature(this, *proto_id);
 }
 
-int32_t DexFile::FindTryItem(const CodeItem &code_item, uint32_t address) {
-  // Note: Signed type is important for max and min.
-  int32_t min = 0;
-  int32_t max = code_item.tries_size_ - 1;
+int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
+  uint32_t min = 0;
+  uint32_t max = tries_size;
+  while (min < max) {
+    const uint32_t mid = (min + max) / 2;
 
-  while (min <= max) {
-    int32_t mid = min + ((max - min) / 2);
-
-    const art::DexFile::TryItem* ti = GetTryItems(code_item, mid);
-    uint32_t start = ti->start_addr_;
-    uint32_t end = start + ti->insn_count_;
+    const art::DexFile::TryItem& ti = try_items[mid];
+    const uint32_t start = ti.start_addr_;
+    const uint32_t end = start + ti.insn_count_;
 
     if (address < start) {
-      max = mid - 1;
+      max = mid;
     } else if (address >= end) {
       min = mid + 1;
     } else {  // We have a winner!
@@ -509,12 +509,8 @@
 }
 
 int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address) {
-  int32_t try_item = FindTryItem(code_item, address);
-  if (try_item == -1) {
-    return -1;
-  } else {
-    return DexFile::GetTryItems(code_item, try_item)->handler_off_;
-  }
+  int32_t try_item = FindTryItem(GetTryItems(code_item, 0), code_item.tries_size_, address);
+  return (try_item == -1) ? -1 : DexFile::GetTryItems(code_item, try_item)->handler_off_;
 }
 
 bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 5c9b258..cdefb23 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;
 
@@ -751,17 +753,23 @@
     return begin_ + call_site_id.data_off_;
   }
 
+  static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
   static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset);
 
   // Get the base of the encoded data for the given DexCode.
-  static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+  static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
+                                            uint32_t tries_size,
+                                            uint32_t offset) {
     const uint8_t* handler_data =
-        reinterpret_cast<const uint8_t*>(GetTryItems(code_item, code_item.tries_size_));
+        reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
     return handler_data + offset;
   }
+  static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+    return GetCatchHandlerData(code_item.Instructions().end(), code_item.tries_size_, offset);
+  }
 
   // Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
-  static int32_t FindTryItem(const CodeItem &code_item, uint32_t address);
+  static int32_t FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address);
 
   // Find the handler offset associated with the given address (ie dex pc). Returns -1 if none.
   static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address);
@@ -993,13 +1001,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 +1017,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 +1084,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;
@@ -1178,6 +1192,11 @@
   bool HasNextVirtualMethod() const {
     return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos();
   }
+  bool HasNextMethod() const {
+    const bool result = pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfVirtualMethodsPos();
+    DCHECK_EQ(result, HasNextDirectMethod() || HasNextVirtualMethod());
+    return result;
+  }
   void SkipStaticFields() {
     while (HasNextStaticField()) {
       Next();
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
index 3411586..874d8ea 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -158,7 +158,7 @@
     if (class_data != nullptr) {
       ClassDataItemIterator cdit(*dex_file_, class_data);
       cdit.SkipAllFields();
-      while (cdit.HasNextDirectMethod()) {
+      while (cdit.HasNextMethod()) {
         const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
         if (code_item != nullptr) {
           const void* code_item_begin = reinterpret_cast<const void*>(code_item);
@@ -178,7 +178,7 @@
     if (class_data != nullptr) {
       ClassDataItemIterator cdit(*dex_file_, class_data);
       cdit.SkipAllFields();
-      while (cdit.HasNextDirectMethod()) {
+      while (cdit.HasNextMethod()) {
         const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
         if (code_item != nullptr) {
           const void* code_item_begin = reinterpret_cast<const void*>(code_item);
@@ -200,7 +200,7 @@
     if (class_data != nullptr) {
       ClassDataItemIterator cdit(*dex_file_, class_data);
       cdit.SkipAllFields();
-      while (cdit.HasNextDirectMethod()) {
+      while (cdit.HasNextMethod()) {
         const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
         if (code_item != nullptr) {
           const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
@@ -221,7 +221,7 @@
     if (class_data != nullptr) {
       ClassDataItemIterator cdit(*dex_file_, class_data);
       cdit.SkipAllFields();
-      while (cdit.HasNextDirectMethod()) {
+      while (cdit.HasNextMethod()) {
         const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex());
         const char * methodid_name = dex_file_->GetMethodName(methodid_item);
         const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 50f56c7..025952f 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -1970,7 +1970,7 @@
     return field->class_idx_;
   }
 
-  if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+  if (it.HasNextMethod()) {
     LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
                 *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return method->class_idx_;
@@ -2566,7 +2566,7 @@
       return false;
     }
   }
-  for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+  for (; it.HasNextMethod(); it.Next()) {
     uint32_t code_off = it.GetMethodCodeItemOffset();
     if (code_off != 0 && !CheckOffsetToTypeMap(code_off, DexFile::kDexTypeCodeItem)) {
       return false;
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index ee577e7..d4d912c 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -249,7 +249,7 @@
     it.Next();
   }
 
-  while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+  while (it.HasNextMethod()) {
     uint32_t method_index = it.GetMemberIndex();
     dex::StringIndex name_index = dex_file->GetMethodId(method_index).name_idx_;
     const DexFile::StringId& string_id = dex_file->GetStringId(name_index);
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/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 805b9c1..bb8e5e5 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -1034,7 +1034,7 @@
     return kProfileLoadBadData;
   }
   const uint8_t* base_ptr = buffer.GetCurrentPtr();
-  std::copy_n(base_ptr, bytes, &data->bitmap_storage[0]);
+  std::copy_n(base_ptr, bytes, data->bitmap_storage.data());
   buffer.Advance(bytes);
   // Read method bitmap.
   return kProfileLoadSuccess;
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/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 378ce2c..b8a13da 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -99,28 +99,7 @@
       << " vdex_fd=" << vdex_fd;;
   }
 
-  // Try to get the realpath for the dex location.
-  //
-  // This is OK with respect to dalvik cache naming scheme because we never
-  // generate oat files starting from symlinks which go into dalvik cache.
-  // (recall that the oat files in dalvik cache are encoded by replacing '/'
-  // with '@' in the path).
-  // The boot image oat files (which are symlinked in dalvik-cache) are not
-  // loaded via the oat file assistant.
-  //
-  // The only case when the dex location may resolve to a different path
-  // is for secondary dex files (e.g. /data/user/0 symlinks to /data/data and
-  // the app is free to create its own internal layout). Related to this it is
-  // worthwhile to mention that installd resolves the secondary dex location
-  // before calling dex2oat.
-  UniqueCPtr<const char[]> dex_location_real(realpath(dex_location, nullptr));
-  if (dex_location_real != nullptr) {
-    dex_location_.assign(dex_location_real.get());
-  } else {
-    // If we can't get the realpath of the location there's not much point in trying to move on.
-    PLOG(ERROR) << "Could not get the realpath of dex_location " << dex_location;
-    return;
-  }
+  dex_location_.assign(dex_location);
 
   if (load_executable_ && isa != kRuntimeISA) {
     LOG(WARNING) << "OatFileAssistant: Load executable specified, "
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 65d01a4..7694f45 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -351,50 +351,6 @@
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
 }
 
-// Case: We have a DEX file and up-to-date OAT file for it. We load the dex file
-// via a symlink.
-// Expect: The status is kNoDexOptNeeded.
-TEST_F(OatFileAssistantTest, OatUpToDateSymLink) {
-  if (IsExecutedAsRoot()) {
-    // We cannot simulate non writable locations when executed as root: b/38000545.
-    LOG(ERROR) << "Test skipped because it's running as root";
-    return;
-  }
-
-  std::string real = GetScratchDir() + "/real";
-  ASSERT_EQ(0, mkdir(real.c_str(), 0700));
-  std::string link = GetScratchDir() + "/link";
-  ASSERT_EQ(0, symlink(real.c_str(), link.c_str()));
-
-  std::string dex_location = real + "/OatUpToDate.jar";
-
-  Copy(GetDexSrc1(), dex_location);
-  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
-  // Update the dex location to point to the symlink.
-  dex_location = link + "/OatUpToDate.jar";
-
-  // For the use of oat location by making the dex parent not writable.
-  ScopedNonWritable scoped_non_writable(dex_location);
-  ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
-
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
-  EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
-
-  EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
-  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
-  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
 // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no
 // ODEX file.
 TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {
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;
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 7b0ef80..9f55314 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -307,6 +307,8 @@
 // Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
 // individual thread requires polling. delay_us is the requested sleep wait. If delay_us is 0 then
 // we use sched_yield instead of calling usleep.
+// Although there is the possibility, here and elsewhere, that usleep could return -1 and
+// errno = EINTR, there should be no problem if interrupted, so we do not check.
 static void ThreadSuspendSleep(useconds_t delay_us) {
   if (delay_us == 0) {
     sched_yield();
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index 9bb875c..a7fa9f3 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -27,10 +27,6 @@
 namespace art {
 namespace verifier {
 
-inline const DexFile::CodeItem* MethodVerifier::CodeItem() const {
-  return code_item_;
-}
-
 inline RegisterLine* MethodVerifier::GetRegLine(uint32_t dex_pc) {
   return reg_table_.GetLine(dex_pc);
 }
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 121f3cf..a75157d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -564,7 +564,7 @@
       dex_cache_(dex_cache),
       class_loader_(class_loader),
       class_def_(class_def),
-      code_item_(code_item),
+      code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
       declaring_class_(nullptr),
       interesting_dex_pc_(-1),
       monitor_enter_dex_pcs_(nullptr),
@@ -616,29 +616,21 @@
   verifier.FindLocksAtDexPc();
 }
 
-static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) {
-  for (const DexInstructionPcPair& inst : code_item->Instructions()) {
-    if (inst->Opcode() == Instruction::MONITOR_ENTER) {
-      return true;
-    }
-  }
-  return false;
-}
-
 void MethodVerifier::FindLocksAtDexPc() {
   CHECK(monitor_enter_dex_pcs_ != nullptr);
-  CHECK(code_item_ != nullptr);  // This only makes sense for methods with code.
+  CHECK(code_item_accessor_.HasCodeItem());  // This only makes sense for methods with code.
 
-  // Quick check whether there are any monitor_enter instructions at all.
-  if (!HasMonitorEnterInstructions(code_item_)) {
-    return;
+  // Quick check whether there are any monitor_enter instructions before verifying.
+  for (const DexInstructionPcPair& inst : code_item_accessor_) {
+    if (inst->Opcode() == Instruction::MONITOR_ENTER) {
+      // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+      // verification. In practice, the phase we want relies on data structures set up by all the
+      // earlier passes, so we just run the full method verification and bail out early when we've
+      // got what we wanted.
+      Verify();
+      return;
+    }
   }
-
-  // Strictly speaking, we ought to be able to get away with doing a subset of the full method
-  // verification. In practice, the phase we want relies on data structures set up by all the
-  // earlier passes, so we just run the full method verification and bail out early when we've
-  // got what we wanted.
-  Verify();
 }
 
 ArtField* MethodVerifier::FindAccessedFieldAtDexPc(ArtMethod* m, uint32_t dex_pc) {
@@ -663,7 +655,7 @@
 }
 
 ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
-  CHECK(code_item_ != nullptr);  // This only makes sense for methods with code.
+  CHECK(code_item_accessor_.HasCodeItem());  // This only makes sense for methods with code.
 
   // Strictly speaking, we ought to be able to get away with doing a subset of the full method
   // verification. In practice, the phase we want relies on data structures set up by all the
@@ -677,7 +669,7 @@
   if (register_line == nullptr) {
     return nullptr;
   }
-  const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+  const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
   return GetQuickFieldAccess(inst, register_line);
 }
 
@@ -703,7 +695,7 @@
 }
 
 ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
-  CHECK(code_item_ != nullptr);  // This only makes sense for methods with code.
+  CHECK(code_item_accessor_.HasCodeItem());  // This only makes sense for methods with code.
 
   // Strictly speaking, we ought to be able to get away with doing a subset of the full method
   // verification. In practice, the phase we want relies on data structures set up by all the
@@ -717,7 +709,7 @@
   if (register_line == nullptr) {
     return nullptr;
   }
-  const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+  const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
   const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
   return GetQuickInvokedMethod(inst, register_line, is_range, false);
 }
@@ -769,7 +761,7 @@
   }
 
   // If there aren't any instructions, make sure that's expected, then exit successfully.
-  if (code_item_ == nullptr) {
+  if (!code_item_accessor_.HasCodeItem()) {
     // Only native or abstract methods may not have code.
     if ((method_access_flags_ & (kAccNative | kAccAbstract)) == 0) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "zero-length code in concrete non-native method";
@@ -861,17 +853,19 @@
   }
 
   // Sanity-check the register counts. ins + locals = registers, so make sure that ins <= registers.
-  if (code_item_->ins_size_ > code_item_->registers_size_) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins=" << code_item_->ins_size_
-                                      << " regs=" << code_item_->registers_size_;
+  if (code_item_accessor_.InsSize() > code_item_accessor_.RegistersSize()) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins="
+                                      << code_item_accessor_.InsSize()
+                                      << " regs=" << code_item_accessor_.RegistersSize();
     return false;
   }
 
   // Allocate and initialize an array to hold instruction data.
-  insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(code_item_->insns_size_in_code_units_));
+  insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(
+      code_item_accessor_.InsnsSizeInCodeUnits()));
   DCHECK(insn_flags_ != nullptr);
   std::uninitialized_fill_n(insn_flags_.get(),
-                            code_item_->insns_size_in_code_units_,
+                            code_item_accessor_.InsnsSizeInCodeUnits(),
                             InstructionFlags());
   // Run through the instructions and see if the width checks out.
   bool result = ComputeWidthsAndCountOps();
@@ -923,7 +917,7 @@
         // Note: this can fail before we touch any instruction, for the signature of a method. So
         //       add a check.
         if (work_insn_idx_ < dex::kDexNoIndex) {
-          const Instruction& inst = code_item_->InstructionAt(work_insn_idx_);
+          const Instruction& inst = code_item_accessor_.InstructionAt(work_insn_idx_);
           int opcode_flags = Instruction::FlagsOf(inst.Opcode());
 
           if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
@@ -986,15 +980,14 @@
   size_t new_instance_count = 0;
   size_t monitor_enter_count = 0;
 
-  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
   // We can't assume the instruction is well formed, handle the case where calculating the size
   // goes past the end of the code item.
-  SafeDexInstructionIterator it(instructions.begin(), instructions.end());
-  for ( ; !it.IsErrorState() && it < instructions.end(); ++it) {
+  SafeDexInstructionIterator it(code_item_accessor_.begin(), code_item_accessor_.end());
+  for ( ; !it.IsErrorState() && it < code_item_accessor_.end(); ++it) {
     // In case the instruction goes past the end of the code item, make sure to not process it.
     SafeDexInstructionIterator next = it;
     ++next;
-    if (next.IsErrorState() || next > instructions.end()) {
+    if (next.IsErrorState()) {
       break;
     }
     Instruction::Code opcode = it->Opcode();
@@ -1021,8 +1014,8 @@
     GetInstructionFlags(it.DexPc()).SetIsOpcode();
   }
 
-  if (it != instructions.end()) {
-    const size_t insns_size = code_item_->insns_size_in_code_units_;
+  if (it != code_item_accessor_.end()) {
+    const size_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected ("
                                       << it.DexPc() << " vs. " << insns_size << ")";
     return false;
@@ -1034,17 +1027,14 @@
 }
 
 bool MethodVerifier::ScanTryCatchBlocks() {
-  uint32_t tries_size = code_item_->tries_size_;
+  const uint32_t tries_size = code_item_accessor_.TriesSize();
   if (tries_size == 0) {
     return true;
   }
-  uint32_t insns_size = code_item_->insns_size_in_code_units_;
-  const DexFile::TryItem* tries = DexFile::GetTryItems(*code_item_, 0);
-
-  for (uint32_t idx = 0; idx < tries_size; idx++) {
-    const DexFile::TryItem* try_item = &tries[idx];
-    uint32_t start = try_item->start_addr_;
-    uint32_t end = start + try_item->insn_count_;
+  const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
+  for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) {
+    const uint32_t start = try_item.start_addr_;
+    const uint32_t end = start + try_item.insn_count_;
     if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad exception entry: startAddr=" << start
                                         << " endAddr=" << end << " (size=" << insns_size << ")";
@@ -1055,18 +1045,14 @@
           << "'try' block starts inside an instruction (" << start << ")";
       return false;
     }
-    uint32_t dex_pc = start;
-    const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
-    while (dex_pc < end) {
-      GetInstructionFlags(dex_pc).SetInTry();
-      size_t insn_size = inst->SizeInCodeUnits();
-      dex_pc += insn_size;
-      inst = inst->RelativeAt(insn_size);
+    DexInstructionIterator end_it(code_item_accessor_.Insns(), end);
+    for (DexInstructionIterator it(code_item_accessor_.Insns(), start); it < end_it; ++it) {
+      GetInstructionFlags(it.DexPc()).SetInTry();
     }
   }
   // Iterate over each of the handlers to verify target addresses.
-  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
-  uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+  const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
+  const uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   for (uint32_t idx = 0; idx < handlers_size; idx++) {
     CatchHandlerIterator iterator(handlers_ptr);
@@ -1077,7 +1063,7 @@
             << "exception handler starts at bad address (" << dex_pc << ")";
         return false;
       }
-      if (!CheckNotMoveResult(code_item_->insns_, dex_pc)) {
+      if (!CheckNotMoveResult(code_item_accessor_.Insns(), dex_pc)) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD)
             << "exception handler begins with move-result* (" << dex_pc << ")";
         return false;
@@ -1105,7 +1091,7 @@
   /* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */
   GetInstructionFlags(0).SetBranchTarget();
   GetInstructionFlags(0).SetCompileTimeInfoPoint();
-  for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+  for (const DexInstructionPcPair& inst : code_item_accessor_) {
     const uint32_t dex_pc = inst.DexPc();
     if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&inst.Inst(), dex_pc)) {
       DCHECK_NE(failures_.size(), 0U);
@@ -1259,18 +1245,18 @@
 }
 
 inline bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
-  if (UNLIKELY(idx >= code_item_->registers_size_)) {
+  if (UNLIKELY(idx >= code_item_accessor_.RegistersSize())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register index out of range (" << idx << " >= "
-                                      << code_item_->registers_size_ << ")";
+                                      << code_item_accessor_.RegistersSize() << ")";
     return false;
   }
   return true;
 }
 
 inline bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
-  if (UNLIKELY(idx + 1 >= code_item_->registers_size_)) {
+  if (UNLIKELY(idx + 1 >= code_item_accessor_.RegistersSize())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register index out of range (" << idx
-                                      << "+1 >= " << code_item_->registers_size_ << ")";
+                                      << "+1 >= " << code_item_accessor_.RegistersSize() << ")";
     return false;
   }
   return true;
@@ -1387,8 +1373,8 @@
 }
 
 bool MethodVerifier::CheckArrayData(uint32_t cur_offset) {
-  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
-  const uint16_t* insns = code_item_->insns_ + cur_offset;
+  const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
+  const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
   const uint16_t* array_data;
   int32_t array_data_offset;
 
@@ -1451,10 +1437,9 @@
                                       << reinterpret_cast<void*>(cur_offset) << " +" << offset;
     return false;
   }
-  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
   int32_t abs_offset = cur_offset + offset;
   if (UNLIKELY(abs_offset < 0 ||
-               (uint32_t) abs_offset >= insn_count ||
+               (uint32_t) abs_offset >= code_item_accessor_.InsnsSizeInCodeUnits()  ||
                !GetInstructionFlags(abs_offset).IsOpcode())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> "
                                       << reinterpret_cast<void*>(abs_offset) << ") at "
@@ -1467,7 +1452,7 @@
 
 bool MethodVerifier::GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
                                   bool* selfOkay) {
-  const uint16_t* insns = code_item_->insns_ + cur_offset;
+  const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
   *pConditional = false;
   *selfOkay = false;
   switch (*insns & 0xff) {
@@ -1503,9 +1488,9 @@
 }
 
 bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) {
-  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
+  const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
   DCHECK_LT(cur_offset, insn_count);
-  const uint16_t* insns = code_item_->insns_ + cur_offset;
+  const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
   /* make sure the start of the switch is in range */
   int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
   if (UNLIKELY(static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
@@ -1610,7 +1595,7 @@
 }
 
 bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
-  uint16_t registers_size = code_item_->registers_size_;
+  uint16_t registers_size = code_item_accessor_.RegistersSize();
   for (uint32_t idx = 0; idx < vA; idx++) {
     if (UNLIKELY(arg[idx] >= registers_size)) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index (" << arg[idx]
@@ -1623,7 +1608,7 @@
 }
 
 bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) {
-  uint16_t registers_size = code_item_->registers_size_;
+  uint16_t registers_size = code_item_accessor_.RegistersSize();
   // vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of
   // integer overflow when adding them here.
   if (UNLIKELY(vA + vC > registers_size)) {
@@ -1635,13 +1620,12 @@
 }
 
 bool MethodVerifier::VerifyCodeFlow() {
-  uint16_t registers_size = code_item_->registers_size_;
-  uint32_t insns_size = code_item_->insns_size_in_code_units_;
+  const uint16_t registers_size = code_item_accessor_.RegistersSize();
 
   /* Create and initialize table holding register status */
   reg_table_.Init(kTrackCompilerInterestPoints,
                   insn_flags_.get(),
-                  insns_size,
+                  code_item_accessor_.InsnsSizeInCodeUnits(),
                   registers_size,
                   this);
 
@@ -1681,7 +1665,7 @@
 }
 
 void MethodVerifier::Dump(VariableIndentationOutputStream* vios) {
-  if (code_item_ == nullptr) {
+  if (!code_item_accessor_.HasCodeItem()) {
     vios->Stream() << "Native method\n";
     return;
   }
@@ -1693,7 +1677,7 @@
   vios->Stream() << "Dumping instructions and register lines:\n";
   ScopedIndentation indent1(vios);
 
-  for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+  for (const DexInstructionPcPair& inst : code_item_accessor_) {
     const size_t dex_pc = inst.DexPc();
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != nullptr) {
@@ -1729,10 +1713,10 @@
   RegisterLine* reg_line = reg_table_.GetLine(0);
 
   // Should have been verified earlier.
-  DCHECK_GE(code_item_->registers_size_, code_item_->ins_size_);
+  DCHECK_GE(code_item_accessor_.RegistersSize(), code_item_accessor_.InsSize());
 
-  uint32_t arg_start = code_item_->registers_size_ - code_item_->ins_size_;
-  size_t expected_args = code_item_->ins_size_;   /* long/double count as two */
+  uint32_t arg_start = code_item_accessor_.RegistersSize() - code_item_accessor_.InsSize();
+  size_t expected_args = code_item_accessor_.InsSize();   /* long/double count as two */
 
   // Include the "this" pointer.
   size_t cur_arg = 0;
@@ -1884,8 +1868,8 @@
 }
 
 bool MethodVerifier::CodeFlowVerifyMethod() {
-  const uint16_t* insns = code_item_->insns_;
-  const uint32_t insns_size = code_item_->insns_size_in_code_units_;
+  const uint16_t* insns = code_item_accessor_.Insns();
+  const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
 
   /* Begin by marking the first instruction as "changed". */
   GetInstructionFlags(0).SetChanged();
@@ -1960,7 +1944,7 @@
      */
     int dead_start = -1;
 
-    for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+    for (const DexInstructionPcPair& inst : code_item_accessor_) {
       const uint32_t insn_idx = inst.DexPc();
       /*
        * Switch-statement data doesn't get "visited" by scanner. It
@@ -1989,7 +1973,7 @@
     if (dead_start >= 0) {
       LogVerifyInfo()
           << "dead code " << reinterpret_cast<void*>(dead_start)
-          << "-" << reinterpret_cast<void*>(code_item_->insns_size_in_code_units_ - 1);
+          << "-" << reinterpret_cast<void*>(code_item_accessor_.InsnsSizeInCodeUnits() - 1);
     }
     // To dump the state of the verify after a method, do something like:
     // if (dex_file_->PrettyMethod(dex_method_idx_) ==
@@ -2075,7 +2059,7 @@
    *
    * The behavior can be determined from the opcode flags.
    */
-  const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+  const uint16_t* insns = code_item_accessor_.Insns() + work_insn_idx_;
   const Instruction* inst = Instruction::At(insns);
   int opcode_flags = Instruction::FlagsOf(inst->Opcode());
 
@@ -2375,7 +2359,7 @@
         while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
           prev_idx--;
         }
-        const Instruction& prev_inst = code_item_->InstructionAt(prev_idx);
+        const Instruction& prev_inst = code_item_accessor_.InstructionAt(prev_idx);
         switch (prev_inst.Opcode()) {
           case Instruction::MOVE_OBJECT:
           case Instruction::MOVE_OBJECT_16:
@@ -2683,7 +2667,7 @@
         break;
       }
 
-      const Instruction& instance_of_inst = code_item_->InstructionAt(instance_of_idx);
+      const Instruction& instance_of_inst = code_item_accessor_.InstructionAt(instance_of_idx);
 
       /* Check for peep-hole pattern of:
        *    ...;
@@ -2722,7 +2706,8 @@
             (orig_type.IsZero() ||
                 orig_type.IsStrictlyAssignableFrom(
                     cast_type.Merge(orig_type, &reg_types_, this), this))) {
-          RegisterLine* update_line = RegisterLine::Create(code_item_->registers_size_, this);
+          RegisterLine* update_line = RegisterLine::Create(code_item_accessor_.RegistersSize(),
+                                                           this);
           if (inst->Opcode() == Instruction::IF_EQZ) {
             fallthrough_line.reset(update_line);
           } else {
@@ -2745,7 +2730,7 @@
                             work_insn_idx_)) {
               break;
             }
-            const Instruction& move_inst = code_item_->InstructionAt(move_idx);
+            const Instruction& move_inst = code_item_accessor_.InstructionAt(move_idx);
             switch (move_inst.Opcode()) {
               case Instruction::MOVE_OBJECT:
                 if (move_inst.VRegA_12x() == instance_of_inst.VRegB_22c()) {
@@ -3564,7 +3549,8 @@
       return false;
     }
     DCHECK_EQ(isConditional, (opcode_flags & Instruction::kContinue) != 0);
-    if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, work_insn_idx_ + branch_target)) {
+    if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(),
+                                           work_insn_idx_ + branch_target)) {
       return false;
     }
     /* update branch target, set "changed" if appropriate */
@@ -3609,8 +3595,8 @@
       offset = switch_insns[offset_to_targets + targ * 2] |
          (static_cast<int32_t>(switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
       abs_offset = work_insn_idx_ + offset;
-      DCHECK_LT(abs_offset, code_item_->insns_size_in_code_units_);
-      if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, abs_offset)) {
+      DCHECK_LT(abs_offset, code_item_accessor_.InsnsSizeInCodeUnits());
+      if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(), abs_offset)) {
         return false;
       }
       if (!UpdateRegisters(abs_offset, work_line_.get(), false)) {
@@ -3625,7 +3611,9 @@
    */
   if ((opcode_flags & Instruction::kThrow) != 0 && GetInstructionFlags(work_insn_idx_).IsInTry()) {
     bool has_catch_all_handler = false;
-    CatchHandlerIterator iterator(*code_item_, work_insn_idx_);
+    const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(work_insn_idx_);
+    CHECK(try_item != nullptr);
+    CatchHandlerIterator iterator(code_item_accessor_.GetCatchHandlerData(try_item->handler_off_));
 
     // Need the linker to try and resolve the handled class to check if it's Throwable.
     ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -3682,15 +3670,15 @@
    *        and this change should not be used in those cases.
    */
   if ((opcode_flags & Instruction::kContinue) != 0) {
-    DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst);
+    DCHECK_EQ(&code_item_accessor_.InstructionAt(work_insn_idx_), inst);
     uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits();
-    if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+    if (next_insn_idx >= code_item_accessor_.InsnsSizeInCodeUnits()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
       return false;
     }
     // The only way to get to a move-exception instruction is to get thrown there. Make sure the
     // next instruction isn't one.
-    if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+    if (!CheckNotMoveException(code_item_accessor_.Insns(), next_insn_idx)) {
       return false;
     }
     if (nullptr != fallthrough_line) {
@@ -3699,7 +3687,7 @@
     }
     if (GetInstructionFlags(next_insn_idx).IsReturn()) {
       // For returns we only care about the operand to the return, all other registers are dead.
-      const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
+      const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn_idx);
       AdjustReturnLine(this, ret_inst, work_line_.get());
     }
     RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
@@ -3731,14 +3719,14 @@
    * alone and let the caller sort it out.
    */
   if ((opcode_flags & Instruction::kContinue) != 0) {
-    DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+    DCHECK_EQ(&code_item_accessor_.InstructionAt(work_insn_idx_), inst);
     *start_guess = work_insn_idx_ + inst->SizeInCodeUnits();
   } else if ((opcode_flags & Instruction::kBranch) != 0) {
     /* we're still okay if branch_target is zero */
     *start_guess = work_insn_idx_ + branch_target;
   }
 
-  DCHECK_LT(*start_guess, code_item_->insns_size_in_code_units_);
+  DCHECK_LT(*start_guess, code_item_accessor_.InsnsSizeInCodeUnits());
   DCHECK(GetInstructionFlags(*start_guess).IsOpcode());
 
   if (have_pending_runtime_throw_failure_) {
@@ -3821,8 +3809,8 @@
 
 const RegType& MethodVerifier::GetCaughtExceptionType() {
   const RegType* common_super = nullptr;
-  if (code_item_->tries_size_ != 0) {
-    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+  if (code_item_accessor_.TriesSize() != 0) {
+    const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
     uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
     for (uint32_t i = 0; i < handlers_size; i++) {
       CatchHandlerIterator iterator(handlers_ptr);
@@ -4041,9 +4029,10 @@
   /* caught by static verifier */
   DCHECK(is_range || expected_args <= 5);
 
-  if (expected_args > code_item_->outs_size_) {
+  if (expected_args > code_item_accessor_.OutsSize()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
-                                      << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+                                      << ") exceeds outsSize ("
+                                      << code_item_accessor_.OutsSize() << ")";
     return nullptr;
   }
 
@@ -4554,9 +4543,9 @@
   const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
   /* caught by static verifier */
   DCHECK(is_range || expected_args <= 5);
-  if (expected_args > code_item_->outs_size_) {
+  if (expected_args > code_item_accessor_.OutsSize()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
-        << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+        << ") exceeds outsSize (" << code_item_accessor_.OutsSize() << ")";
     return nullptr;
   }
 
@@ -5142,8 +5131,7 @@
   }
 }
 
-ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
-                                                      RegisterLine* reg_line) {
+ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) {
   DCHECK(IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) << inst->Opcode();
   const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c());
   if (!object_type.HasClass()) {
@@ -5330,7 +5318,7 @@
 
       // For returns we only care about the operand to the return, all other registers are dead.
       // Initialize them as conflicts so they don't add to GC and deoptimization information.
-      const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
+      const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn);
       AdjustReturnLine(this, ret_inst, target_line);
       // Directly bail if a hard failure was found.
       if (have_pending_hard_failure_) {
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 1f1d7c1..813ce87 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -25,6 +25,7 @@
 #include "base/macros.h"
 #include "base/scoped_arena_containers.h"
 #include "base/value_object.h"
+#include "code_item_accessors.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
 #include "handle.h"
@@ -186,7 +187,9 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Accessors used by the compiler via CompilerCallback
-  const DexFile::CodeItem* CodeItem() const;
+  const CodeItemDataAccessor& CodeItem() const {
+    return code_item_accessor_;
+  }
   RegisterLine* GetRegLine(uint32_t dex_pc);
   ALWAYS_INLINE const InstructionFlags& GetInstructionFlags(size_t index) const;
   ALWAYS_INLINE InstructionFlags& GetInstructionFlags(size_t index);
@@ -738,7 +741,7 @@
   // The class loader for the declaring class of the method.
   Handle<mirror::ClassLoader> class_loader_ GUARDED_BY(Locks::mutator_lock_);
   const DexFile::ClassDef& class_def_;  // The class def of the declaring class of the method.
-  const DexFile::CodeItem* const code_item_;  // The code item containing the code for the method.
+  const CodeItemDataAccessor code_item_accessor_;
   const RegType* declaring_class_;  // Lazily computed reg type of the method's declaring class.
   // Instruction widths and flags, one entry per code unit.
   // Owned, but not unique_ptr since insn_flags_ are allocated in arenas.
diff --git a/test/163-app-image-methods/src/Main.java b/test/163-app-image-methods/src/Main.java
index a995bb8..c513470 100644
--- a/test/163-app-image-methods/src/Main.java
+++ b/test/163-app-image-methods/src/Main.java
@@ -22,6 +22,9 @@
             // Allocate memory for the "AAA.Derived" class name before eating memory.
             String aaaDerivedName = "AAA.Derived";
             System.out.println("Eating all memory.");
+            // Resolve VMClassLoader before eating all the memory since we can not fail
+            // initializtaion of boot classpath classes.
+            Class.forName("java.lang.VMClassLoader");
             Object memory = eatAllMemory();
 
             // This test assumes that Derived is not yet resolved. In some configurations
diff --git a/test/165-lock-owner-proxy/src/Main.java b/test/165-lock-owner-proxy/src/Main.java
index 1b1694d..fff8e58 100644
--- a/test/165-lock-owner-proxy/src/Main.java
+++ b/test/165-lock-owner-proxy/src/Main.java
@@ -65,8 +65,13 @@
             int count = totalOperations;
             while (count > 0) {
                 synchronized (lockObject) {
-                    inf.foo(10000 - count, 11000 - count, 12000 - count, 13000 - count,
-                          14000 - count, 15000 - count);
+                    try {
+                        inf.foo(10000 - count, 11000 - count, 12000 - count, 13000 - count,
+                                14000 - count, 15000 - count);
+                    } catch (OutOfMemoryError e) {
+                        // Ignore errors. This is the test for b/69121347 - see an exception
+                        // instead of native abort.
+                    }
               }
               count--;
             }
@@ -96,7 +101,12 @@
             while (!finish) {
                 // Some random allocations adding up to almost 2M.
                 for (int i = 0; i < 188; i++) {
-                    byte b[] = new byte[i * 100 + 10];
+                    try {
+                        byte b[] = new byte[i * 100 + 10];
+                    } catch (OutOfMemoryError e) {
+                        // Ignore. This is just to improve chances that an OOME is thrown during
+                        // proxy invocation.
+                    }
                 }
                 try {
                     Thread.sleep(10);
diff --git a/test/669-moveable-string-class-equals/run b/test/669-moveable-string-class-equals/run
index d0ab6f8..7c74d8c 100755
--- a/test/669-moveable-string-class-equals/run
+++ b/test/669-moveable-string-class-equals/run
@@ -16,4 +16,4 @@
 
 # Run without image, so that String.class is moveable.
 # Reduce heap size to force more frequent GCs.
-${RUN} --no-image --no-dex2oat --runtime-option -Xmx16m "$@"
+${RUN} --no-image --runtime-option -Xmx16m "$@"
diff --git a/test/669-moveable-string-class-equals/src/Main.java b/test/669-moveable-string-class-equals/src/Main.java
index 4badade..d182d51 100644
--- a/test/669-moveable-string-class-equals/src/Main.java
+++ b/test/669-moveable-string-class-equals/src/Main.java
@@ -43,6 +43,10 @@
       array[i] = "V" + i;
     }
 
+    // Continually check string equality between a newly allocated String and an
+    // already allocated String with the same contents while allocating over 128MiB
+    // memory (with heap size limited to 16MiB), ensuring we run GC and stress the
+    // instanceof check in the String.equals() implementation.
     for (int count = 0; count != 128 * 1024; ++count) {
       for (int i = 0; i != length; ++i) {
         allocateAtLeast1KiB();
diff --git a/test/913-heaps/build b/test/913-heaps/build
deleted file mode 100644
index 10ffcc5..0000000
--- a/test/913-heaps/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/913-heaps/check b/test/913-heaps/check
index 8358500..f4892d0 100644
--- a/test/913-heaps/check
+++ b/test/913-heaps/check
@@ -14,9 +14,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Jack has a different set of bytecode offsets/method IDs in the expected.txt
+# Jack/D8 has a different set of bytecode offsets/method IDs in the expected.txt
+
 if [[ "$USE_JACK" == true ]]; then
   patch -p0 expected.txt < expected_jack.diff
+elif [[ "$USE_D8" == true ]]; then
+  patch -p0 expected.txt < expected_d8.diff
 fi
 
 ./default-check "$@"
diff --git a/test/913-heaps/expected_d8.diff b/test/913-heaps/expected_d8.diff
new file mode 100644
index 0000000..8369422
--- /dev/null
+++ b/test/913-heaps/expected_d8.diff
@@ -0,0 +1,76 @@
+4,5c4
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
+< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
+49c48
+< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
+51c50,51
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+102,103c102
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
+< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
+115c114
+< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
+117c116,117
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+162c162
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
+177c177
+< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
+179c179,180
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+201,202c202,203
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
+< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 164])--> 1000@0 [size=123456780050, length=-1]
+246c247
+< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
+248c249,251
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 164])--> 1000@0 [size=123456780055, length=-1]
+292c295
+< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 181])--> 1000@0 [size=123456780060, length=-1]
+319a323
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 181])--> 1000@0 [size=123456780065, length=-1]
+347c351
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
+366c370
+< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
+368c372,373
+< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+---
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 69e4b87..8755f04 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -40,46 +40,22 @@
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS)
 
 # Also need libartagent.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libartagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libartagentd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libartagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libartagentd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libartagent-target libartagentd-target
 
 # Also need libtiagent.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtiagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtiagentd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagentd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libtiagent-target libtiagentd-target
 
 # Also need libtistress.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistress)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistressd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistress)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistressd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libtistress-target libtistressd-target
 
 # Also need libarttest.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttest)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttestd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libarttest)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libarttestd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libarttest-target libarttestd-target
 
 # Also need libnativebridgetest.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libnativebridgetest)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libnativebridgetest)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libnativebridgetest-target
 
 # Also need libopenjdkjvmti.
-TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti
-TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmtid
+TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti-target libopenjdkjvmtid-target
 
 TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar
 TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 53b5093..fd9ad0b 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -35,7 +35,7 @@
 using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK)
 
 java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES
-common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target libjdwp"
+common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target"
 mode="target"
 j_arg="-j$(nproc)"
 showcommands=
@@ -70,16 +70,23 @@
 extra_args=SOONG_ALLOW_MISSING_DEPENDENCIES=true
 
 if [[ $mode == "host" ]]; then
-  make_command="make $j_arg $extra_args $showcommands build-art-host-tests $common_targets dx-tests"
-  make_command+=" ${out_dir}/host/linux-x86/lib/libjavacoretests.so "
-  make_command+=" ${out_dir}/host/linux-x86/lib64/libjavacoretests.so"
-  make_command+=" libwrapagentpropertiesd libwrapagentproperties"
+  make_command="make $j_arg $extra_args $showcommands build-art-host-tests $common_targets"
+  make_command+=" dx-tests"
+  mode_suffix="-host"
 elif [[ $mode == "target" ]]; then
   make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
-  make_command+=" libjavacrypto libjavacoretests libnetd_client linker toybox toolbox sh"
+  make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
   make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
   make_command+=" ${out_dir}/target/product/${TARGET_PRODUCT}/system/etc/public.libraries.txt"
+  mode_suffix="-target"
 fi
 
+mode_specific_libraries="libjavacoretests libjdwp libwrapagentproperties libwrapagentpropertiesd"
+for LIB in ${mode_specific_libraries} ; do
+  make_command+=" $LIB${mode_suffix}"
+done
+
+
+
 echo "Executing $make_command"
 $make_command
diff --git a/tools/libjdwp_oj_art_failures.txt b/tools/libjdwp_oj_art_failures.txt
index e0f243c..787c4d2 100644
--- a/tools/libjdwp_oj_art_failures.txt
+++ b/tools/libjdwp_oj_art_failures.txt
@@ -61,5 +61,11 @@
            "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.NameTest#testName001_NullObject",
            "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ParentTest#testParent_NullObject",
            "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ]
+},
+{
+  description: "Test is flaky",
+  result: EXEC_FAILED,
+  bug: 69121056,
+  name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001"
 }
 ]
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index db8c540..f5fbcd8 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -284,8 +284,10 @@
 
 if [[ $using_jack == "true" ]]; then
   toolchain_args="--toolchain jack --language JN --jack-arg -g"
-else
+elif [[ $mode != "ri" ]]; then
   toolchain_args="--toolchain dx --language CUR"
+else
+  toolchain_args="--toolchain javac --language CUR"
 fi
 
 # Run the tests using vogar.