Merge "Add JVMTI DDMS extension method and event."
diff --git a/Android.mk b/Android.mk
index 7081f7b..174cde3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -484,7 +484,7 @@
 ########################################################################
 # Phony target for building what go/lem requires for syncing /system to target.
 .PHONY: build-art-unbundled-golem
-build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS)
+build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS) crash_dump
 
 ########################################################################
 # Rules for building all dependencies for tests.
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/build/art.go b/build/art.go
index 4e48d2d..5704b43 100644
--- a/build/art.go
+++ b/build/art.go
@@ -46,10 +46,6 @@
 		cflags = append(cflags, "-DART_USE_TLAB=1")
 	}
 
-	if !envFalse(ctx, "ART_ENABLE_VDEX") {
-		cflags = append(cflags, "-DART_ENABLE_VDEX")
-	}
-
 	imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
 	cflags = append(cflags, "-DIMT_SIZE="+imtSize)
 
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/code_generator_vector_mips.cc b/compiler/optimizing/code_generator_vector_mips.cc
index 384b642..3cf150a 100644
--- a/compiler/optimizing/code_generator_vector_mips.cc
+++ b/compiler/optimizing/code_generator_vector_mips.cc
@@ -1071,11 +1071,195 @@
 
 void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
+  LocationSummary* locations = instruction->GetLocations();
+  // All conversions require at least one temporary register.
+  locations->AddTemp(Location::RequiresFpuRegister());
+  // Some conversions require a second temporary register.
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+            HVecOperation::ToSignedType(b->GetPackedType()));
+  switch (a->GetPackedType()) {
+    case DataType::Type::kInt32:
+      if (instruction->GetPackedType() == DataType::Type::kInt32) {
+        break;
+      }
+      FALLTHROUGH_INTENDED;
+    case DataType::Type::kUint8:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      locations->AddTemp(Location::RequiresFpuRegister());
+      break;
+    default:
+      break;
+  }
 }
 
 void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
-  // TODO: implement this, location helper already filled out (shared with MulAcc).
+  LocationSummary* locations = instruction->GetLocations();
+  VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+  VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+  VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+  VectorRegister tmp = static_cast<VectorRegister>(FTMP);
+  VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
+
+  DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+  // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+            HVecOperation::ToSignedType(b->GetPackedType()));
+  switch (a->GetPackedType()) {
+    case DataType::Type::kUint8:
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16: {
+          DCHECK_EQ(8u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ AddvH(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ AddvH(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ AddvW(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillH(tmp, ZERO);
+          __ Hadd_sW(tmp1, left, tmp);
+          __ Hadd_sW(tmp2, right, tmp);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ AddvW(acc, acc, tmp1);
+          __ Hadd_sW(tmp1, tmp, left);
+          __ Hadd_sW(tmp2, tmp, right);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillH(tmp, ZERO);
+          __ Hadd_sW(tmp1, left, tmp);
+          __ Hadd_sW(tmp2, right, tmp);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sW(tmp1, tmp, left);
+          __ Hadd_sW(tmp2, tmp, right);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          __ FillW(tmp, ZERO);
+          __ SubvW(tmp1, left, right);
+          __ Add_aW(tmp1, tmp1, tmp);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillW(tmp, ZERO);
+          __ Hadd_sD(tmp1, left, tmp);
+          __ Hadd_sD(tmp2, right, tmp);
+          __ Asub_sD(tmp1, tmp1, tmp2);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sD(tmp1, tmp, left);
+          __ Hadd_sD(tmp2, tmp, right);
+          __ Asub_sD(tmp1, tmp1, tmp2);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt64: {
+      DCHECK_EQ(2u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          __ FillW(tmp, ZERO);
+          __ SubvD(tmp1, left, right);
+          __ Add_aD(tmp1, tmp1, tmp);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector memory operations.
diff --git a/compiler/optimizing/code_generator_vector_mips64.cc b/compiler/optimizing/code_generator_vector_mips64.cc
index 0c59b73..2d69533 100644
--- a/compiler/optimizing/code_generator_vector_mips64.cc
+++ b/compiler/optimizing/code_generator_vector_mips64.cc
@@ -1069,11 +1069,195 @@
 
 void LocationsBuilderMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
+  LocationSummary* locations = instruction->GetLocations();
+  // All conversions require at least one temporary register.
+  locations->AddTemp(Location::RequiresFpuRegister());
+  // Some conversions require a second temporary register.
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+            HVecOperation::ToSignedType(b->GetPackedType()));
+  switch (a->GetPackedType()) {
+    case DataType::Type::kInt32:
+      if (instruction->GetPackedType() == DataType::Type::kInt32) {
+        break;
+      }
+      FALLTHROUGH_INTENDED;
+    case DataType::Type::kUint8:
+    case DataType::Type::kInt8:
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      locations->AddTemp(Location::RequiresFpuRegister());
+      break;
+    default:
+      break;
+  }
 }
 
 void InstructionCodeGeneratorMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
-  // TODO: implement this, location helper already filled out (shared with MulAcc).
+  LocationSummary* locations = instruction->GetLocations();
+  VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+  VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+  VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+  VectorRegister tmp = static_cast<VectorRegister>(FTMP);
+  VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
+
+  DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+  // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+            HVecOperation::ToSignedType(b->GetPackedType()));
+  switch (a->GetPackedType()) {
+    case DataType::Type::kUint8:
+    case DataType::Type::kInt8:
+      DCHECK_EQ(16u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kUint16:
+        case DataType::Type::kInt16: {
+          DCHECK_EQ(8u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ AddvH(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ AddvH(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ AddvW(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillB(tmp, ZERO);
+          __ Hadd_sH(tmp1, left, tmp);
+          __ Hadd_sH(tmp2, right, tmp);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sH(tmp1, tmp, left);
+          __ Hadd_sH(tmp2, tmp, right);
+          __ Asub_sH(tmp1, tmp1, tmp2);
+          __ Hadd_sW(tmp1, tmp1, tmp1);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kUint16:
+    case DataType::Type::kInt16:
+      DCHECK_EQ(8u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillH(tmp, ZERO);
+          __ Hadd_sW(tmp1, left, tmp);
+          __ Hadd_sW(tmp2, right, tmp);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ AddvW(acc, acc, tmp1);
+          __ Hadd_sW(tmp1, tmp, left);
+          __ Hadd_sW(tmp2, tmp, right);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillH(tmp, ZERO);
+          __ Hadd_sW(tmp1, left, tmp);
+          __ Hadd_sW(tmp2, right, tmp);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sW(tmp1, tmp, left);
+          __ Hadd_sW(tmp2, tmp, right);
+          __ Asub_sW(tmp1, tmp1, tmp2);
+          __ Hadd_sD(tmp1, tmp1, tmp1);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt32:
+      DCHECK_EQ(4u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(4u, instruction->GetVectorLength());
+          __ FillW(tmp, ZERO);
+          __ SubvW(tmp1, left, right);
+          __ Add_aW(tmp1, tmp1, tmp);
+          __ AddvW(acc, acc, tmp1);
+          break;
+        }
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+          __ FillW(tmp, ZERO);
+          __ Hadd_sD(tmp1, left, tmp);
+          __ Hadd_sD(tmp2, right, tmp);
+          __ Asub_sD(tmp1, tmp1, tmp2);
+          __ AddvD(acc, acc, tmp1);
+          __ Hadd_sD(tmp1, tmp, left);
+          __ Hadd_sD(tmp2, tmp, right);
+          __ Asub_sD(tmp1, tmp1, tmp2);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    case DataType::Type::kInt64: {
+      DCHECK_EQ(2u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt64: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          __ FillD(tmp, ZERO);
+          __ SubvD(tmp1, left, right);
+          __ Add_aD(tmp1, tmp1, tmp);
+          __ AddvD(acc, acc, tmp1);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector memory operations.
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 4d846fa..7adb196 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1672,7 +1672,7 @@
                         compiler_driver_,
                         codegen_,
                         inline_stats_,
-                        resolved_method->GetQuickenedInfo(class_linker->GetImagePointerSize()),
+                        resolved_method->GetQuickenedInfo(),
                         handles_);
 
   if (builder.BuildGraph() != kAnalysisSuccess) {
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/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 69c5827..fcc59ea 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1512,17 +1512,17 @@
           case DataType::Type::kBool:
           case DataType::Type::kUint8:
           case DataType::Type::kInt8:
-            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(16);
           case DataType::Type::kUint16:
           case DataType::Type::kInt16:
-            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
+            *restrictions |= kNoDiv | kNoStringCharAt;
             return TrySetVectorLength(8);
           case DataType::Type::kInt32:
-            *restrictions |= kNoDiv | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(4);
           case DataType::Type::kInt64:
-            *restrictions |= kNoDiv | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(2);
           case DataType::Type::kFloat32:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
@@ -1541,17 +1541,17 @@
           case DataType::Type::kBool:
           case DataType::Type::kUint8:
           case DataType::Type::kInt8:
-            *restrictions |= kNoDiv | kNoReduction | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(16);
           case DataType::Type::kUint16:
           case DataType::Type::kInt16:
-            *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
+            *restrictions |= kNoDiv | kNoStringCharAt;
             return TrySetVectorLength(8);
           case DataType::Type::kInt32:
-            *restrictions |= kNoDiv | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(4);
           case DataType::Type::kInt64:
-            *restrictions |= kNoDiv | kNoSAD;
+            *restrictions |= kNoDiv;
             return TrySetVectorLength(2);
           case DataType::Type::kFloat32:
             *restrictions |= kNoMinMax | kNoReduction;  // min/max(x, NaN)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 252d538..2bba985 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1007,7 +1007,7 @@
   if (method != nullptr) {
     graph->SetArtMethod(method);
     ScopedObjectAccess soa(Thread::Current());
-    interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize());
+    interpreter_metadata = method->GetQuickenedInfo();
   }
 
   std::unique_ptr<CodeGenerator> codegen(
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9fa7f69..8137fb1 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1565,7 +1565,7 @@
         // 2) when we have a vdex file, which means it was already verified.
         const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr);
         if (!oat_writers_[i]->WriteAndOpenDexFiles(
-            kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
+            vdex_files_[i].get(),
             rodata_.back(),
             instruction_set_,
             instruction_set_features_.get(),
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/image_test.h b/dex2oat/linker/image_test.h
index d3d42b9..cedbccf 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -269,7 +269,7 @@
         std::unique_ptr<MemMap> cur_opened_dex_files_map;
         std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files;
         bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles(
-            kIsVdexEnabled ? vdex_files[i].GetFile() : oat_files[i].GetFile(),
+            vdex_files[i].GetFile(),
             rodata.back(),
             driver->GetInstructionSet(),
             driver->GetInstructionSetFeatures(),
@@ -293,14 +293,12 @@
       bool image_space_ok = writer->PrepareImageAddressSpace();
       ASSERT_TRUE(image_space_ok);
 
-      if (kIsVdexEnabled) {
-        for (size_t i = 0, size = vdex_files.size(); i != size; ++i) {
-          std::unique_ptr<BufferedOutputStream> vdex_out =
-              std::make_unique<BufferedOutputStream>(
-                  std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
-          oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr);
-          oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get());
-        }
+      for (size_t i = 0, size = vdex_files.size(); i != size; ++i) {
+        std::unique_ptr<BufferedOutputStream> vdex_out =
+            std::make_unique<BufferedOutputStream>(
+                std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
+        oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr);
+        oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get());
       }
 
       for (size_t i = 0, size = oat_files.size(); i != size; ++i) {
diff --git a/dex2oat/linker/multi_oat_relative_patcher.h b/dex2oat/linker/multi_oat_relative_patcher.h
index 6683366..d97be8d 100644
--- a/dex2oat/linker/multi_oat_relative_patcher.h
+++ b/dex2oat/linker/multi_oat_relative_patcher.h
@@ -26,7 +26,6 @@
 namespace art {
 
 class CompiledMethod;
-class LinkerPatch;
 class InstructionSetFeatures;
 
 namespace linker {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d8671d2..d3e920f 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -571,10 +571,9 @@
   std::vector<std::unique_ptr<const DexFile>> dex_files;
 
   // Initialize VDEX and OAT headers.
-  if (kIsVdexEnabled) {
-    // Reserve space for Vdex header and checksums.
-    vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
-  }
+
+  // Reserve space for Vdex header and checksums.
+  vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
   oat_size_ = InitOatHeader(instruction_set,
                             instruction_set_features,
                             dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
@@ -582,28 +581,12 @@
 
   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
 
-  if (kIsVdexEnabled) {
-    std::unique_ptr<BufferedOutputStream> vdex_out =
-        std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
-    // Write DEX files into VDEX, mmap and open them.
-    if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
-        !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
-      return false;
-    }
-  } else {
-    DCHECK(!update_input_vdex);
-    // Write DEX files into OAT, mmap and open them.
-    if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
-        !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
-      return false;
-    }
-
-    // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
-    // difficult because we're not using the OutputStream directly.
-    if (!oat_dex_files_.empty()) {
-      size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
-      oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
-    }
+  std::unique_ptr<BufferedOutputStream> vdex_out =
+      std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
+  // Write DEX files into VDEX, mmap and open them.
+  if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
+      !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
+    return false;
   }
 
   // Write type lookup tables into the oat file.
@@ -755,13 +738,12 @@
 };
 
 static bool HasCompiledCode(const CompiledMethod* method) {
-  // The dextodexcompiler puts the quickening info table into the CompiledMethod
-  // for simplicity. For such methods, we will emit an OatQuickMethodHeader
-  // only when vdex is disabled.
-  return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
+  return method != nullptr && !method->GetQuickCode().empty();
 }
 
 static bool HasQuickeningInfo(const CompiledMethod* method) {
+  // The dextodexcompiler puts the quickening info table into the CompiledMethod
+  // for simplicity.
   return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
 }
 
@@ -1214,23 +1196,17 @@
     // The code offset was 0 when the mapping/vmap table offset was set, so it's set
     // to 0-offset and we need to adjust it by code_offset.
     uint32_t code_offset = quick_code_offset - thumb_offset;
-    if (!compiled_method->GetQuickCode().empty()) {
-      // If the code is compiled, we write the offset of the stack map relative
-      // to the code,
-      if (vmap_table_offset != 0u) {
-        vmap_table_offset += code_offset;
-        DCHECK_LT(vmap_table_offset, code_offset);
-      }
-      if (method_info_offset != 0u) {
-        method_info_offset += code_offset;
-        DCHECK_LT(method_info_offset, code_offset);
-      }
-    } else {
-      CHECK(!kIsVdexEnabled);
-      // We write the offset of the quickening info relative to the code.
+    CHECK(!compiled_method->GetQuickCode().empty());
+    // If the code is compiled, we write the offset of the stack map relative
+    // to the code.
+    if (vmap_table_offset != 0u) {
       vmap_table_offset += code_offset;
       DCHECK_LT(vmap_table_offset, code_offset);
     }
+    if (method_info_offset != 0u) {
+      method_info_offset += code_offset;
+      DCHECK_LT(method_info_offset, code_offset);
+    }
     uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
     uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
     uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
@@ -2126,20 +2102,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())) {
@@ -2599,10 +2569,6 @@
 };
 
 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
-  if (!kIsVdexEnabled) {
-    return true;
-  }
-
   size_t initial_offset = vdex_size_;
   size_t start_offset = RoundUp(initial_offset, 4u);
 
@@ -2661,10 +2627,6 @@
 }
 
 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
-  if (!kIsVdexEnabled) {
-    return true;
-  }
-
   if (verifier_deps == nullptr) {
     // Nothing to write. Record the offset, but no need
     // for alignment.
@@ -3176,23 +3138,17 @@
   }
 
   // Update current size and account for the written data.
-  if (kIsVdexEnabled) {
-    DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
-    vdex_size_ += oat_dex_file->dex_file_size_;
-  } else {
-    DCHECK(!update_input_vdex);
-    DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
-    oat_size_ += oat_dex_file->dex_file_size_;
-  }
+  DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
+  vdex_size_ += oat_dex_file->dex_file_size_;
   size_dex_file_ += oat_dex_file->dex_file_size_;
   return true;
 }
 
 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
   // Dex files are required to be 4 byte aligned.
-  size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
+  size_t initial_offset = vdex_size_;
   size_t start_offset = RoundUp(initial_offset, 4);
-  size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
+  size_t file_offset = start_offset;
   size_dex_file_alignment_ += start_offset - initial_offset;
 
   // Seek to the start of the dex file and flush any pending operations in the stream.
@@ -3217,11 +3173,7 @@
     return false;
   }
 
-  if (kIsVdexEnabled) {
-    vdex_size_ = start_offset;
-  } else {
-    oat_size_ = start_offset;
-  }
+  vdex_size_ = start_offset;
   oat_dex_file->dex_file_offset_ = start_offset;
   return true;
 }
@@ -3297,7 +3249,7 @@
                              File* file,
                              OatDexFile* oat_dex_file,
                              ZipEntry* dex_file) {
-  size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+  size_t start_offset = vdex_size_;
   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
 
   // Extract the dex file and get the extracted size.
@@ -3390,7 +3342,7 @@
                              File* file,
                              OatDexFile* oat_dex_file,
                              File* dex_file) {
-  size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+  size_t start_offset = vdex_size_;
   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
 
   off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
@@ -3486,7 +3438,7 @@
   }
 
   size_t map_offset = oat_dex_files_[0].dex_file_offset_;
-  size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
+  size_t length = vdex_size_ - map_offset;
 
   std::string error_msg;
   std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
@@ -3494,7 +3446,7 @@
       PROT_READ | PROT_WRITE,
       MAP_SHARED,
       file->Fd(),
-      kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
+      map_offset,
       /* low_4gb */ false,
       file->GetPath().c_str(),
       &error_msg));
@@ -3698,9 +3650,6 @@
 }
 
 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
-  if (!kIsVdexEnabled) {
-    return true;
-  }
   // Write checksums
   off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
   if (actual_offset != sizeof(VdexFile::Header)) {
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 1ee2e4e..022aa1b 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -192,7 +192,7 @@
     OutputStream* oat_rodata = elf_writer->StartRoData();
     std::unique_ptr<MemMap> opened_dex_files_map;
     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-    if (!oat_writer.WriteAndOpenDexFiles(kIsVdexEnabled ? vdex_file : oat_file,
+    if (!oat_writer.WriteAndOpenDexFiles(vdex_file,
                                          oat_rodata,
                                          compiler_driver_->GetInstructionSet(),
                                          compiler_driver_->GetInstructionSetFeatures(),
@@ -224,15 +224,13 @@
                                       oat_writer.GetBssMethodsOffset(),
                                       oat_writer.GetBssRootsOffset());
 
-    if (kIsVdexEnabled) {
-      std::unique_ptr<BufferedOutputStream> vdex_out =
-            std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
-      if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) {
-        return false;
-      }
-      if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) {
-        return false;
-      }
+    std::unique_ptr<BufferedOutputStream> vdex_out =
+        std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
+    if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) {
+      return false;
+    }
+    if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) {
+      return false;
     }
 
     if (!oat_writer.WriteRodata(oat_rodata)) {
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..5a3d34c 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,
@@ -572,46 +573,36 @@
     }
 
     if (options_.export_dex_location_) {
-      if (kIsVdexEnabled) {
-        std::string error_msg;
-        std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
-        if (!OS::FileExists(vdex_filename.c_str())) {
-          os << "File " << vdex_filename.c_str() << " does not exist\n";
-          return false;
-        }
+      std::string error_msg;
+      std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
+      if (!OS::FileExists(vdex_filename.c_str())) {
+        os << "File " << vdex_filename.c_str() << " does not exist\n";
+        return false;
+      }
 
-        DexFileUniqV vdex_dex_files;
-        std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
-                                                                      &vdex_dex_files,
-                                                                      &error_msg);
-        if (vdex_file.get() == nullptr) {
-          os << "Failed to open vdex file: " << error_msg << "\n";
-          return false;
-        }
-        if (oat_dex_files_.size() != vdex_dex_files.size()) {
-          os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
-             << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
-          return false;
-        }
+      DexFileUniqV vdex_dex_files;
+      std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
+                                                                    &vdex_dex_files,
+                                                                    &error_msg);
+      if (vdex_file.get() == nullptr) {
+        os << "Failed to open vdex file: " << error_msg << "\n";
+        return false;
+      }
+      if (oat_dex_files_.size() != vdex_dex_files.size()) {
+        os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
+           << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
+        return false;
+      }
 
-        size_t i = 0;
-        for (const auto& vdex_dex_file : vdex_dex_files) {
-          const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
-          CHECK(oat_dex_file != nullptr);
-          CHECK(vdex_dex_file != nullptr);
-          if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) {
-            success = false;
-          }
-          i++;
+      size_t i = 0;
+      for (const auto& vdex_dex_file : vdex_dex_files) {
+        const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
+        CHECK(oat_dex_file != nullptr);
+        CHECK(vdex_dex_file != nullptr);
+        if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) {
+          success = false;
         }
-      } else {
-        for (size_t i = 0; i < oat_dex_files_.size(); i++) {
-          const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
-          CHECK(oat_dex_file != nullptr);
-          if (!ExportDexFile(os, *oat_dex_file, /* vdex_dex_file */ nullptr)) {
-            success = false;
-          }
-        }
+        i++;
       }
     }
 
@@ -893,11 +884,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 +966,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 +977,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 +1211,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 +1237,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 +1258,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 +1281,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 +1357,7 @@
       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
 
       size_t vmap_table_offset_limit =
-          (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
+          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 +1369,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 +1390,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 +1432,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 +1445,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 +1483,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 +1508,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 +1523,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 +1541,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 +1552,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 +1567,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 +1585,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 +1607,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 +1747,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 +1758,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 +1814,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 +1854,7 @@
                          helper.GetEncoding(),
                          method_info,
                          oat_method.GetCodeOffset(),
-                         code_item->registers_size_,
+                         code_item_accessor.RegistersSize(),
                          instruction_set_);
           do {
             helper.Next();
@@ -2502,8 +2482,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.cc b/runtime/art_method.cc
index 0a108f9..fa0c501 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -563,23 +563,14 @@
   return true;
 }
 
-const uint8_t* ArtMethod::GetQuickenedInfo(PointerSize pointer_size) {
-  if (kIsVdexEnabled) {
-    const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
-    const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
-    if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
-      return nullptr;
-    }
-    return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
-        dex_file, GetCodeItemOffset());
-  } else {
-    bool found = false;
-    OatFile::OatMethod oat_method = FindOatMethodFor(this, pointer_size, &found);
-    if (!found || (oat_method.GetQuickCode() != nullptr)) {
-      return nullptr;
-    }
-    return oat_method.GetVmapTable();
+const uint8_t* ArtMethod::GetQuickenedInfo() {
+  const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
+  const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+  if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
+    return nullptr;
   }
+  return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
+      dex_file, GetCodeItemOffset());
 }
 
 const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 0e98d47..dca6f37 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"
@@ -462,7 +464,7 @@
     // where the declaring class is treated as a weak reference (accessing it with
     // a read barrier would either prevent unloading the class, or crash the runtime if
     // the GC wants to unload it).
-    DCHECK(!IsNative());
+    DCHECK(!IsNative<kWithoutReadBarrier>());
     if (UNLIKELY(IsProxyMethod())) {
       return nullptr;
     }
@@ -655,7 +657,7 @@
     return hotness_count_;
   }
 
-  const uint8_t* GetQuickenedInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_);
+  const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns the method header for the compiled code containing 'pc'. Note that runtime
   // methods will return null for this method, as they are not oat based.
@@ -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/dex_instruction.cc b/runtime/dex_instruction.cc
index e64c0f6..6ebe228 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -548,4 +548,14 @@
   return os << Instruction::Name(code);
 }
 
+uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const {
+  DCHECK_LT(operand_index, GetNumberOfOperands());
+  return first_operand_ + operand_index;
+}
+
+uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const {
+  DCHECK_LT(operand_index, GetNumberOfOperands());
+  return operands_[operand_index];
+}
+
 }  // namespace art
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 09c78b2..4041820 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -689,6 +689,53 @@
 std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
 std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
 
+// Base class for accessing instruction operands. Unifies operand
+// access for instructions that have range and varargs forms
+// (e.g. invoke-polymoprhic/range and invoke-polymorphic).
+class InstructionOperands {
+ public:
+  explicit InstructionOperands(size_t num_operands) : num_operands_(num_operands) {}
+  virtual ~InstructionOperands() {}
+  virtual uint32_t GetOperand(size_t index) const = 0;
+  size_t GetNumberOfOperands() const { return num_operands_; }
+
+ private:
+  size_t num_operands_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
+};
+
+// Class for accessing operands for instructions with a range format
+// (e.g. 3rc and 4rcc).
+class RangeInstructionOperands FINAL : public InstructionOperands {
+ public:
+  RangeInstructionOperands(uint32_t first_operand, size_t num_operands)
+      : InstructionOperands(num_operands), first_operand_(first_operand) {}
+  ~RangeInstructionOperands() {}
+  uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+  const uint32_t first_operand_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(RangeInstructionOperands);
+};
+
+// Class for accessing operands for instructions with a variable
+// number of arguments format (e.g. 35c and 45cc).
+class VarArgsInstructionOperands FINAL : public InstructionOperands {
+ public:
+  VarArgsInstructionOperands(const uint32_t (&operands)[Instruction::kMaxVarArgRegs],
+                             size_t num_operands)
+      : InstructionOperands(num_operands), operands_(operands) {}
+  ~VarArgsInstructionOperands() {}
+  uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+  const uint32_t (&operands_)[Instruction::kMaxVarArgRegs];
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
+};
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_DEX_INSTRUCTION_H_
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 127b5d7..22c9a1d 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2649,28 +2649,24 @@
 
   // Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
   // consecutive order.
-  uint32_t unused_args[Instruction::kMaxVarArgRegs] = {};
-  uint32_t first_callee_arg = first_arg + 1;
-
+  RangeInstructionOperands operands(first_arg + 1, num_vregs - 1);
   bool isExact = (jni::EncodeArtMethod(resolved_method) ==
                   WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
   bool success = false;
   if (isExact) {
-    success = MethodHandleInvokeExact<true/*is_range*/>(self,
-                                                        *shadow_frame,
-                                                        method_handle,
-                                                        method_type,
-                                                        unused_args,
-                                                        first_callee_arg,
-                                                        result);
+    success = MethodHandleInvokeExact(self,
+                                      *shadow_frame,
+                                      method_handle,
+                                      method_type,
+                                      &operands,
+                                      result);
   } else {
-    success = MethodHandleInvoke<true/*is_range*/>(self,
-                                                   *shadow_frame,
-                                                   method_handle,
-                                                   method_type,
-                                                   unused_args,
-                                                   first_callee_arg,
-                                                   result);
+    success = MethodHandleInvoke(self,
+                                 *shadow_frame,
+                                 method_handle,
+                                 method_type,
+                                 &operands,
+                                 result);
   }
   DCHECK(success || self->IsExceptionPending());
 
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/gc/task_processor.cc b/runtime/gc/task_processor.cc
index e928644..64e8322 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -23,32 +23,37 @@
 namespace gc {
 
 TaskProcessor::TaskProcessor()
-    : lock_(new Mutex("Task processor lock", kReferenceProcessorLock)), is_running_(false),
+    : lock_("Task processor lock", kReferenceProcessorLock),
+      cond_("Task processor condition", lock_),
+      is_running_(false),
       running_thread_(nullptr) {
-  // Piggyback off the reference processor lock level.
-  cond_.reset(new ConditionVariable("Task processor condition", *lock_));
 }
 
 TaskProcessor::~TaskProcessor() {
-  delete lock_;
+  if (!tasks_.empty()) {
+    LOG(WARNING) << "TaskProcessor: Finalizing " << tasks_.size() << " unprocessed tasks.";
+    for (HeapTask* task : tasks_) {
+      task->Finalize();
+    }
+  }
 }
 
 void TaskProcessor::AddTask(Thread* self, HeapTask* task) {
   ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
-  MutexLock mu(self, *lock_);
+  MutexLock mu(self, lock_);
   tasks_.insert(task);
-  cond_->Signal(self);
+  cond_.Signal(self);
 }
 
 HeapTask* TaskProcessor::GetTask(Thread* self) {
   ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
-  MutexLock mu(self, *lock_);
+  MutexLock mu(self, lock_);
   while (true) {
     if (tasks_.empty()) {
       if (!is_running_) {
         return nullptr;
       }
-      cond_->Wait(self);  // Empty queue, wait until we are signalled.
+      cond_.Wait(self);  // Empty queue, wait until we are signalled.
     } else {
       // Non empty queue, look at the top element and see if we are ready to run it.
       const uint64_t current_time = NanoTime();
@@ -61,18 +66,18 @@
         return task;
       }
       DCHECK_GT(target_time, current_time);
-      // Wait untl we hit the target run time.
+      // Wait until we hit the target run time.
       const uint64_t delta_time = target_time - current_time;
       const uint64_t ms_delta = NsToMs(delta_time);
       const uint64_t ns_delta = delta_time - MsToNs(ms_delta);
-      cond_->TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
+      cond_.TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
     }
   }
   UNREACHABLE();
 }
 
 void TaskProcessor::UpdateTargetRunTime(Thread* self, HeapTask* task, uint64_t new_target_time) {
-  MutexLock mu(self, *lock_);
+  MutexLock mu(self, lock_);
   // Find the task.
   auto range = tasks_.equal_range(task);
   for (auto it = range.first; it != range.second; ++it) {
@@ -85,7 +90,7 @@
         // If we became the first task then we may need to signal since we changed the task that we
         // are sleeping on.
         if (*tasks_.begin() == task) {
-          cond_->Signal(self);
+          cond_.Signal(self);
         }
         return;
       }
@@ -94,24 +99,24 @@
 }
 
 bool TaskProcessor::IsRunning() const {
-  MutexLock mu(Thread::Current(), *lock_);
+  MutexLock mu(Thread::Current(), lock_);
   return is_running_;
 }
 
 Thread* TaskProcessor::GetRunningThread() const {
-  MutexLock mu(Thread::Current(), *lock_);
+  MutexLock mu(Thread::Current(), lock_);
   return running_thread_;
 }
 
 void TaskProcessor::Stop(Thread* self) {
-  MutexLock mu(self, *lock_);
+  MutexLock mu(self, lock_);
   is_running_ = false;
   running_thread_ = nullptr;
-  cond_->Broadcast(self);
+  cond_.Broadcast(self);
 }
 
 void TaskProcessor::Start(Thread* self) {
-  MutexLock mu(self, *lock_);
+  MutexLock mu(self, lock_);
   is_running_ = true;
   running_thread_ = self;
 }
diff --git a/runtime/gc/task_processor.h b/runtime/gc/task_processor.h
index e40fa06..f6b5607 100644
--- a/runtime/gc/task_processor.h
+++ b/runtime/gc/task_processor.h
@@ -54,17 +54,17 @@
  public:
   TaskProcessor();
   virtual ~TaskProcessor();
-  void AddTask(Thread* self, HeapTask* task) REQUIRES(!*lock_);
-  HeapTask* GetTask(Thread* self) REQUIRES(!*lock_);
-  void Start(Thread* self) REQUIRES(!*lock_);
+  void AddTask(Thread* self, HeapTask* task) REQUIRES(!lock_);
+  HeapTask* GetTask(Thread* self) REQUIRES(!lock_);
+  void Start(Thread* self) REQUIRES(!lock_);
   // Stop tells the RunAllTasks to finish up the remaining tasks as soon as
   // possible then return.
-  void Stop(Thread* self) REQUIRES(!*lock_);
-  void RunAllTasks(Thread* self) REQUIRES(!*lock_);
-  bool IsRunning() const REQUIRES(!*lock_);
+  void Stop(Thread* self) REQUIRES(!lock_);
+  void RunAllTasks(Thread* self) REQUIRES(!lock_);
+  bool IsRunning() const REQUIRES(!lock_);
   void UpdateTargetRunTime(Thread* self, HeapTask* target_time, uint64_t new_target_time)
-      REQUIRES(!*lock_);
-  Thread* GetRunningThread() const REQUIRES(!*lock_);
+      REQUIRES(!lock_);
+  Thread* GetRunningThread() const REQUIRES(!lock_);
 
  private:
   class CompareByTargetRunTime {
@@ -74,9 +74,9 @@
     }
   };
 
-  mutable Mutex* lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  ConditionVariable cond_ GUARDED_BY(lock_);
   bool is_running_ GUARDED_BY(lock_);
-  std::unique_ptr<ConditionVariable> cond_ GUARDED_BY(lock_);
   std::multiset<HeapTask*, CompareByTargetRunTime> tasks_ GUARDED_BY(lock_);
   Thread* running_thread_ GUARDED_BY(lock_);
 
diff --git a/runtime/globals.h b/runtime/globals.h
index 53932fd..f14d6e9 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -125,12 +125,6 @@
 
 static constexpr bool kDefaultMustRelocate = true;
 
-#ifdef ART_ENABLE_VDEX
-static constexpr bool kIsVdexEnabled = true;
-#else
-static constexpr bool kIsVdexEnabled = false;
-#endif
-
 // Size of a heap reference.
 static constexpr size_t kHeapReferenceSize = sizeof(uint32_t);
 
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0a1ae36..d2d017e 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -644,52 +644,47 @@
   // arguments either from a range or an array of arguments depending
   // on whether the DEX instruction is invoke-polymorphic/range or
   // invoke-polymorphic. The array here is for the latter.
-  uint32_t args[Instruction::kMaxVarArgRegs] = {};
   if (UNLIKELY(is_range)) {
     // VRegC is the register holding the method handle. Arguments passed
     // to the method handle's target do not include the method handle.
-    uint32_t first_arg = inst->VRegC_4rcc() + 1;
-    static const bool kIsRange = true;
+    RangeInstructionOperands operands(inst->VRegC_4rcc() + 1, inst->VRegA_4rcc() - 1);
     if (invoke_exact) {
-      return art::MethodHandleInvokeExact<kIsRange>(self,
-                                                    shadow_frame,
-                                                    method_handle,
-                                                    callsite_type,
-                                                    args /* unused */,
-                                                    first_arg,
-                                                    result);
+      return MethodHandleInvokeExact(self,
+                                     shadow_frame,
+                                     method_handle,
+                                     callsite_type,
+                                     &operands,
+                                     result);
     } else {
-      return art::MethodHandleInvoke<kIsRange>(self,
-                                               shadow_frame,
-                                               method_handle,
-                                               callsite_type,
-                                               args /* unused */,
-                                               first_arg,
-                                               result);
+      return MethodHandleInvoke(self,
+                                shadow_frame,
+                                method_handle,
+                                callsite_type,
+                                &operands,
+                                result);
     }
   } else {
     // Get the register arguments for the invoke.
+    uint32_t args[Instruction::kMaxVarArgRegs] = {};
     inst->GetVarArgs(args, inst_data);
     // Drop the first register which is the method handle performing the invoke.
     memmove(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1));
     args[Instruction::kMaxVarArgRegs - 1] = 0;
-    static const bool kIsRange = false;
+    VarArgsInstructionOperands operands(args, inst->VRegA_45cc() - 1);
     if (invoke_exact) {
-      return art::MethodHandleInvokeExact<kIsRange>(self,
-                                                    shadow_frame,
-                                                    method_handle,
-                                                    callsite_type,
-                                                    args,
-                                                    args[0],
-                                                    result);
+      return MethodHandleInvokeExact(self,
+                                     shadow_frame,
+                                     method_handle,
+                                     callsite_type,
+                                     &operands,
+                                     result);
     } else {
-      return art::MethodHandleInvoke<kIsRange>(self,
-                                               shadow_frame,
-                                               method_handle,
-                                               callsite_type,
-                                               args,
-                                               args[0],
-                                               result);
+      return MethodHandleInvoke(self,
+                                shadow_frame,
+                                method_handle,
+                                callsite_type,
+                                &operands,
+                                result);
     }
   }
 }
@@ -1180,17 +1175,13 @@
 
   // Invoke the bootstrap method handle.
   JValue result;
-
-  // This array of arguments is unused. DoMethodHandleInvokeExact() operates on either a
-  // an argument array or a range, but always takes an array argument.
-  uint32_t args_unused[Instruction::kMaxVarArgRegs];
-  bool invoke_success = art::MethodHandleInvokeExact<true /* is_range */>(self,
-                                                                          *bootstrap_frame,
-                                                                          bootstrap,
-                                                                          bootstrap_method_type,
-                                                                          args_unused,
-                                                                          0,
-                                                                          &result);
+  RangeInstructionOperands operands(0, vreg);
+  bool invoke_success = MethodHandleInvokeExact(self,
+                                                *bootstrap_frame,
+                                                bootstrap,
+                                                bootstrap_method_type,
+                                                &operands,
+                                                &result);
   if (!invoke_success) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
@@ -1273,21 +1264,25 @@
   Handle<mirror::MethodHandle> target = hs.NewHandle(call_site->GetTarget());
   Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType());
   DCHECK_EQ(static_cast<size_t>(inst->VRegA()), target_method_type->NumberOfVRegs());
-
-  uint32_t args[Instruction::kMaxVarArgRegs];
   if (is_range) {
-    args[0] = inst->VRegC_3rc();
+    RangeInstructionOperands operands(inst->VRegC_3rc(), inst->VRegA_3rc());
+    return MethodHandleInvokeExact(self,
+                                   shadow_frame,
+                                   target,
+                                   target_method_type,
+                                   &operands,
+                                   result);
   } else {
+    uint32_t args[Instruction::kMaxVarArgRegs];
     inst->GetVarArgs(args, inst_data);
+    VarArgsInstructionOperands operands(args, inst->VRegA_35c());
+    return MethodHandleInvokeExact(self,
+                                   shadow_frame,
+                                   target,
+                                   target_method_type,
+                                   &operands,
+                                   result);
   }
-
-  return art::MethodHandleInvokeExact<is_range>(self,
-                                                shadow_frame,
-                                                target,
-                                                target_method_type,
-                                                args,
-                                                args[0],
-                                                result);
 }
 
 template <bool is_range>
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index e180752..3220513 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -30,6 +30,7 @@
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/bitmap-inl.h"
 #include "gc/scoped_gc_critical_section.h"
+#include "handle.h"
 #include "intern_table.h"
 #include "jit/jit.h"
 #include "jit/profiling_info.h"
@@ -38,8 +39,10 @@
 #include "oat_file-inl.h"
 #include "oat_quick_method_header.h"
 #include "object_callbacks.h"
+#include "profile_compilation_info.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
+#include "thread-current-inl.h"
 #include "thread_list.h"
 
 namespace art {
@@ -182,6 +185,8 @@
             << PrettySize(initial_code_capacity);
 }
 
+JitCodeCache::~JitCodeCache() {}
+
 bool JitCodeCache::ContainsPc(const void* ptr) const {
   return code_map_->Begin() <= ptr && ptr < code_map_->End();
 }
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 9790e3a..46a4085 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -24,24 +24,33 @@
 #include "base/histogram-inl.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "gc/accounting/bitmap.h"
 #include "gc_root.h"
-#include "jni.h"
 #include "method_reference.h"
-#include "oat_file.h"
-#include "profile_compilation_info.h"
 #include "safe_map.h"
-#include "thread_pool.h"
 
 namespace art {
 
 class ArtMethod;
+template<class T> class Handle;
 class LinearAlloc;
 class InlineCache;
 class IsMarkedVisitor;
 class OatQuickMethodHeader;
+struct ProfileMethodInfo;
 class ProfilingInfo;
 
+namespace gc {
+namespace accounting {
+template<size_t kAlignment> class MemoryRangeBitmap;
+}  // namespace accounting
+}  // namespace gc
+
+namespace mirror {
+class Class;
+class Object;
+template<class T> class ObjectArray;
+}  // namespace mirror
+
 namespace jit {
 
 class JitInstrumentationCache;
@@ -66,6 +75,7 @@
                               size_t max_capacity,
                               bool generate_debug_info,
                               std::string* error_msg);
+  ~JitCodeCache();
 
   // Number of bytes allocated in the code cache.
   size_t CodeCacheSize() REQUIRES(!lock_);
@@ -210,11 +220,6 @@
 
   uint64_t GetLastUpdateTimeNs() const;
 
-  size_t GetCurrentCapacity() REQUIRES(!lock_) {
-    MutexLock lock(Thread::Current(), lock_);
-    return current_capacity_;
-  }
-
   size_t GetMemorySizeOfCodePointer(const void* ptr) REQUIRES(!lock_);
 
   void InvalidateCompiledCodeFor(ArtMethod* method, const OatQuickMethodHeader* code)
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/method_handles.cc b/runtime/method_handles.cc
index 5a5d571..8eb31c1 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -299,17 +299,14 @@
 
 namespace {
 
-template <bool is_range>
 inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
                                          ShadowFrame* callee_frame,
-                                         const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                         uint32_t first_arg,
-                                         const size_t first_dst_reg,
-                                         const size_t num_regs)
+                                         const InstructionOperands* const operands,
+                                         const size_t first_dst_reg)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  for (size_t i = 0; i < num_regs; ++i) {
+  for (size_t i = 0; i < operands->GetNumberOfOperands(); ++i) {
     size_t dst_reg = first_dst_reg + i;
-    size_t src_reg = is_range ? (first_arg + i) : args[i];
+    size_t src_reg = operands->GetOperand(i);
     // Uint required, so that sign extension does not make this wrong on 64-bit systems
     uint32_t src_value = caller_frame.GetVReg(src_reg);
     ObjPtr<mirror::Object> o = caller_frame.GetVRegReference<kVerifyNone>(src_reg);
@@ -324,15 +321,13 @@
   }
 }
 
-template <bool is_range>
 inline bool ConvertAndCopyArgumentsFromCallerFrame(
     Thread* self,
     Handle<mirror::MethodType> callsite_type,
     Handle<mirror::MethodType> callee_type,
     const ShadowFrame& caller_frame,
-    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-    uint32_t first_arg,
-    uint32_t first_dst_reg,
+    uint32_t first_dest_reg,
+    const InstructionOperands* const operands,
     ShadowFrame* callee_frame)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
@@ -344,15 +339,14 @@
     return false;
   }
 
-  ShadowFrameGetter<is_range> getter(first_arg, args, caller_frame);
-  ShadowFrameSetter setter(callee_frame, first_dst_reg);
-
-  return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
-                                                                            callsite_type,
-                                                                            callee_type,
-                                                                            &getter,
-                                                                            &setter,
-                                                                            num_method_params);
+  ShadowFrameGetter getter(operands, caller_frame);
+  ShadowFrameSetter setter(callee_frame, first_dest_reg);
+  return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self,
+                                                                  callsite_type,
+                                                                  callee_type,
+                                                                  &getter,
+                                                                  &setter,
+                                                                  num_method_params);
 }
 
 inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
@@ -406,14 +400,12 @@
   return false;
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
                                             Handle<mirror::MethodType> callsite_type,
                                             Handle<mirror::MethodType> target_type,
                                             Thread* self,
                                             ShadowFrame& shadow_frame,
-                                            const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                            uint32_t first_arg,
+                                            const InstructionOperands* const operands,
                                             JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
   // Compute method information.
   const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -455,12 +447,10 @@
     if (callsite_type->IsExactMatch(target_type.Get())) {
       // This is an exact invoke, we can take the fast path of just copying all
       // registers without performing any argument conversions.
-      CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
-                                             new_shadow_frame,
-                                             args,
-                                             first_arg,
-                                             first_dest_reg,
-                                             num_input_regs);
+      CopyArgumentsFromCallerFrame(shadow_frame,
+                                   new_shadow_frame,
+                                   operands,
+                                   first_dest_reg);
     } else {
       // This includes the case where we're entering this invoke-polymorphic
       // from a transformer method. In that case, the callsite_type will contain
@@ -471,7 +461,7 @@
         is_caller_transformer = true;
         // The emulated stack frame is the first and only argument when we're coming
         // through from a transformer.
-        size_t first_arg_register = (is_range) ? first_arg : args[0];
+        size_t first_arg_register = operands->GetOperand(0);
         ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
             reinterpret_cast<mirror::EmulatedStackFrame*>(
                 shadow_frame.GetVRegReference(first_arg_register)));
@@ -488,14 +478,13 @@
           ThrowWrongMethodTypeException(target_type.Get(), callsite_type.Get());
           return false;
         }
-        if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
-                                                              callsite_type,
-                                                              target_type,
-                                                              shadow_frame,
-                                                              args,
-                                                              first_arg,
-                                                              first_dest_reg,
-                                                              new_shadow_frame)) {
+        if (!ConvertAndCopyArgumentsFromCallerFrame(self,
+                                                    callsite_type,
+                                                    target_type,
+                                                    shadow_frame,
+                                                    first_dest_reg,
+                                                    operands,
+                                                    new_shadow_frame)) {
           DCHECK(self->IsExceptionPending());
           result->SetL(0);
           return false;
@@ -521,7 +510,7 @@
   // we need to copy the result back out to the emulated stack frame.
   if (is_caller_transformer) {
     StackHandleScope<2> hs(self);
-    size_t first_callee_register = is_range ? (first_arg) : args[0];
+    size_t first_callee_register = operands->GetOperand(0);
     Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
         hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
             shadow_frame.GetVRegReference(first_callee_register))));
@@ -541,15 +530,13 @@
   return ConvertReturnValue(callsite_type, target_type, result);
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
                                                Handle<mirror::MethodType> callsite_type,
                                                Handle<mirror::MethodType> callee_type,
                                                Thread* self,
                                                ShadowFrame& shadow_frame,
                                                Handle<mirror::MethodHandle> receiver,
-                                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                               uint32_t first_arg,
+                                               const InstructionOperands* const operands,
                                                JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // This can be fixed to two, because the method we're calling here
@@ -578,16 +565,15 @@
     // If we're entering this transformer from another transformer, we can pass
     // through the handle directly to the callee, instead of having to
     // instantiate a new stack frame based on the shadow frame.
-    size_t first_callee_register = is_range ? first_arg : args[0];
+    size_t first_callee_register = operands->GetOperand(0);
     sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
         shadow_frame.GetVRegReference(first_callee_register)));
   } else {
-    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(self,
-                                                                                 callsite_type,
-                                                                                 callee_type,
-                                                                                 shadow_frame,
-                                                                                 first_arg,
-                                                                                 args));
+    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs(self,
+                                                                       callsite_type,
+                                                                       callee_type,
+                                                                       shadow_frame,
+                                                                       operands));
 
     // Something went wrong while creating the emulated stack frame, we should
     // throw the pending exception.
@@ -699,13 +685,11 @@
   return target_method;
 }
 
-template <bool is_range>
 bool DoInvokePolymorphicMethod(Thread* self,
                                ShadowFrame& shadow_frame,
                                Handle<mirror::MethodHandle> method_handle,
                                Handle<mirror::MethodType> callsite_type,
-                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                               uint32_t first_arg,
+                               const InstructionOperands* const operands,
                                JValue* result)
   REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
@@ -718,7 +702,7 @@
   // point because they would have been performed on our behalf at the point
   // of creation of the method handle.
   ArtMethod* target_method = method_handle->GetTargetMethod();
-  uint32_t receiver_reg = is_range ? first_arg: args[0];
+  uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
   ArtMethod* called_method = RefineTargetMethod(self,
                                                 shadow_frame,
                                                 handle_kind,
@@ -743,24 +727,22 @@
     Handle<mirror::MethodType> callee_type =
         (handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
         : handle_type;
-    return MethodHandleInvokeTransform<is_range>(called_method,
-                                                 callsite_type,
-                                                 callee_type,
-                                                 self,
-                                                 shadow_frame,
-                                                 method_handle /* receiver */,
-                                                 args,
-                                                 first_arg,
-                                                 result);
+    return MethodHandleInvokeTransform(called_method,
+                                       callsite_type,
+                                       callee_type,
+                                       self,
+                                       shadow_frame,
+                                       method_handle /* receiver */,
+                                       operands,
+                                       result);
   } else {
-    return MethodHandleInvokeMethod<is_range>(called_method,
-                                              callsite_type,
-                                              handle_type,
-                                              self,
-                                              shadow_frame,
-                                              args,
-                                              first_arg,
-                                              result);
+    return MethodHandleInvokeMethod(called_method,
+                                    callsite_type,
+                                    handle_type,
+                                    self,
+                                    shadow_frame,
+                                    operands,
+                                    result);
   }
 }
 
@@ -884,23 +866,21 @@
   return field_value;
 }
 
-template <bool is_range, bool do_conversions>
+template <bool do_conversions>
 bool MethodHandleFieldAccess(Thread* self,
                              ShadowFrame& shadow_frame,
                              Handle<mirror::MethodHandle> method_handle,
                              Handle<mirror::MethodType> callsite_type,
-                             const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                             uint32_t first_arg,
+                             const InstructionOperands* const operands,
                              JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
   Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
   ArtField* field = method_handle->GetTargetField();
   Primitive::Type field_type = field->GetTypeAsPrimitiveType();
-
   switch (handle_kind) {
     case mirror::MethodHandle::kInstanceGet: {
-      size_t obj_reg = is_range ? first_arg : args[0];
+      size_t obj_reg = operands->GetOperand(0);
       ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
       MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
       if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
@@ -923,8 +903,8 @@
       return true;
     }
     case mirror::MethodHandle::kInstancePut: {
-      size_t obj_reg = is_range ? first_arg : args[0];
-      size_t value_reg = is_range ? (first_arg + 1) : args[1];
+      size_t obj_reg = operands->GetOperand(0);
+      size_t value_reg = operands->GetOperand(1);
       const size_t kPTypeIndex = 1;
       // Use ptypes instead of field type since we may be unboxing a reference for a primitive
       // field. The field type is incorrect for this case.
@@ -948,7 +928,7 @@
         DCHECK(self->IsExceptionPending());
         return false;
       }
-      size_t value_reg = is_range ? first_arg : args[0];
+      size_t value_reg = operands->GetOperand(0);
       const size_t kPTypeIndex = 0;
       // Use ptypes instead of field type since we may be unboxing a reference for a primitive
       // field. The field type is incorrect for this case.
@@ -971,13 +951,11 @@
   }
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeInternal(Thread* self,
                                               ShadowFrame& shadow_frame,
                                               Handle<mirror::MethodHandle> method_handle,
                                               Handle<mirror::MethodType> callsite_type,
-                                              const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                              uint32_t first_arg,
+                                              const InstructionOperands* const operands,
                                               JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
@@ -989,32 +967,28 @@
       return false;
     }
     const bool do_convert = true;
-    return MethodHandleFieldAccess<is_range, do_convert>(
+    return MethodHandleFieldAccess<do_convert>(
         self,
         shadow_frame,
         method_handle,
         callsite_type,
-        args,
-        first_arg,
+        operands,
         result);
   }
-  return DoInvokePolymorphicMethod<is_range>(self,
-                                             shadow_frame,
-                                             method_handle,
-                                             callsite_type,
-                                             args,
-                                             first_arg,
-                                             result);
+  return DoInvokePolymorphicMethod(self,
+                                   shadow_frame,
+                                   method_handle,
+                                   callsite_type,
+                                   operands,
+                                   result);
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeExactInternal(
     Thread* self,
     ShadowFrame& shadow_frame,
     Handle<mirror::MethodHandle> method_handle,
     Handle<mirror::MethodType> callsite_type,
-    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-    uint32_t first_arg,
+    const InstructionOperands* const operands,
     JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
@@ -1027,29 +1001,27 @@
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
   if (IsFieldAccess(handle_kind)) {
     const bool do_convert = false;
-    return MethodHandleFieldAccess<is_range, do_convert>(self,
-                                                         shadow_frame,
-                                                         method_handle,
-                                                         callsite_type,
-                                                         args,
-                                                         first_arg,
-                                                         result);
+    return MethodHandleFieldAccess<do_convert>(self,
+                                               shadow_frame,
+                                               method_handle,
+                                               callsite_type,
+                                               operands,
+                                               result);
   }
 
   // Slow-path check.
   if (IsInvokeTransform(handle_kind) || IsCallerTransformer(callsite_type)) {
-    return DoInvokePolymorphicMethod<is_range>(self,
-                                               shadow_frame,
-                                               method_handle,
-                                               callsite_type,
-                                               args,
-                                               first_arg,
-                                               result);
+    return DoInvokePolymorphicMethod(self,
+                                     shadow_frame,
+                                     method_handle,
+                                     callsite_type,
+                                     operands,
+                                     result);
   }
 
   // On the fast-path. This is equivalent to DoCallPolymoprhic without the conversion paths.
   ArtMethod* target_method = method_handle->GetTargetMethod();
-  uint32_t receiver_reg = is_range ? first_arg : args[0];
+  uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
   ArtMethod* called_method = RefineTargetMethod(self,
                                                 shadow_frame,
                                                 handle_kind,
@@ -1085,12 +1057,10 @@
   ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
       CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
   ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
-  CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
-                                         new_shadow_frame,
-                                         args,
-                                         first_arg,
-                                         first_dest_reg,
-                                         num_input_regs);
+  CopyArgumentsFromCallerFrame(shadow_frame,
+                               new_shadow_frame,
+                               operands,
+                               first_dest_reg);
   self->EndAssertNoThreadSuspension(old_cause);
 
   bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
@@ -1110,43 +1080,37 @@
 
 }  // namespace
 
-template <bool is_range>
-inline bool MethodHandleInvoke(Thread* self,
-                                 ShadowFrame& shadow_frame,
-                                 Handle<mirror::MethodHandle> method_handle,
-                                 Handle<mirror::MethodType> callsite_type,
-                                 const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                 uint32_t first_arg,
-                                 JValue* result)
+bool MethodHandleInvoke(Thread* self,
+                       ShadowFrame& shadow_frame,
+                       Handle<mirror::MethodHandle> method_handle,
+                       Handle<mirror::MethodType> callsite_type,
+                       const InstructionOperands* const operands,
+                       JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
     // A non-exact invoke that can be invoked exactly.
-    return MethodHandleInvokeExactInternal<is_range>(self,
-                                                     shadow_frame,
-                                                     method_handle,
-                                                     callsite_type,
-                                                     args,
-                                                     first_arg,
-                                                     result);
+    return MethodHandleInvokeExactInternal(self,
+                                           shadow_frame,
+                                           method_handle,
+                                           callsite_type,
+                                           operands,
+                                           result);
   } else {
-    return MethodHandleInvokeInternal<is_range>(self,
-                                                shadow_frame,
-                                                method_handle,
-                                                callsite_type,
-                                                args,
-                                                first_arg,
-                                                result);
+    return MethodHandleInvokeInternal(self,
+                                      shadow_frame,
+                                      method_handle,
+                                      callsite_type,
+                                      operands,
+                                      result);
   }
 }
 
-template <bool is_range>
 bool MethodHandleInvokeExact(Thread* self,
-                               ShadowFrame& shadow_frame,
-                               Handle<mirror::MethodHandle> method_handle,
-                               Handle<mirror::MethodType> callsite_type,
-                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                               uint32_t first_arg,
-                               JValue* result)
+                             ShadowFrame& shadow_frame,
+                             Handle<mirror::MethodHandle> method_handle,
+                             Handle<mirror::MethodType> callsite_type,
+                             const InstructionOperands* const operands,
+                             JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // We need to check the nominal type of the handle in addition to the
   // real type. The "nominal" type is present when MethodHandle.asType is
@@ -1160,39 +1124,20 @@
     }
     if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
       // Different nominal type means we have to treat as non-exact.
-      return MethodHandleInvokeInternal<is_range>(self,
-                                           shadow_frame,
-                                           method_handle,
-                                           callsite_type,
-                                           args,
-                                           first_arg,
-                                           result);
+      return MethodHandleInvokeInternal(self,
+                                        shadow_frame,
+                                        method_handle,
+                                        callsite_type,
+                                        operands,
+                                        result);
     }
   }
-  return MethodHandleInvokeExactInternal<is_range>(self,
-                                                   shadow_frame,
-                                                   method_handle,
-                                                   callsite_type,
-                                                   args,
-                                                   first_arg,
-                                                   result);
+  return MethodHandleInvokeExactInternal(self,
+                                         shadow_frame,
+                                         method_handle,
+                                         callsite_type,
+                                         operands,
+                                         result);
 }
 
-#define EXPLICIT_DO_METHOD_HANDLE_METHOD(_name, _is_range)       \
-  template REQUIRES_SHARED(Locks::mutator_lock_)                 \
-  bool MethodHandle##_name<_is_range>(                           \
-      Thread* self,                                              \
-      ShadowFrame& shadow_frame,                                 \
-      Handle<mirror::MethodHandle> method_handle,                \
-      Handle<mirror::MethodType> callsite_type,                  \
-      const uint32_t (&args)[Instruction::kMaxVarArgRegs],       \
-      uint32_t first_arg,                                        \
-      JValue* result)
-
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, false);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, false);
-#undef EXPLICIT_DO_METHOD_HANDLE_METHOD
-
 }  // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 930b8db..bc74bf2 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -126,50 +126,40 @@
                         int32_t num_conversions) REQUIRES_SHARED(Locks::mutator_lock_);
 
 // A convenience class that allows for iteration through a list of
-// input argument registers |arg| for non-range invokes or a list of
-// consecutive registers starting with a given based for range
-// invokes.
-//
-// This is used to iterate over input arguments while performing standard
-// argument conversions.
-template <bool is_range>
+// input argument registers. This is used to iterate over input
+// arguments while performing standard argument conversions.
 class ShadowFrameGetter {
  public:
-  ShadowFrameGetter(size_t first_src_reg,
-                    const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                    const ShadowFrame& shadow_frame) :
-      first_src_reg_(first_src_reg),
-      arg_(arg),
-      shadow_frame_(shadow_frame),
-      arg_index_(0) {
-  }
+  ShadowFrameGetter(const InstructionOperands* const operands, const ShadowFrame& shadow_frame)
+      : operands_(operands), operand_index_(0), shadow_frame_(shadow_frame) {}
 
   ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
-    const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
-    ++arg_index_;
-
-    return shadow_frame_.GetVReg(next);
+    return shadow_frame_.GetVReg(Next());
   }
 
   ALWAYS_INLINE int64_t GetLong() REQUIRES_SHARED(Locks::mutator_lock_) {
-    const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
-    arg_index_ += 2;
-
-    return shadow_frame_.GetVRegLong(next);
+    return shadow_frame_.GetVRegLong(NextLong());
   }
 
   ALWAYS_INLINE ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_) {
-    const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
-    ++arg_index_;
-
-    return shadow_frame_.GetVRegReference(next);
+    return shadow_frame_.GetVRegReference(Next());
   }
 
  private:
-  const size_t first_src_reg_;
-  const uint32_t (&arg_)[Instruction::kMaxVarArgRegs];
+  uint32_t Next() {
+    const uint32_t next = operands_->GetOperand(operand_index_);
+    operand_index_ += 1;
+    return next;
+  }
+  uint32_t NextLong() {
+    const uint32_t next = operands_->GetOperand(operand_index_);
+    operand_index_ += 2;
+    return next;
+  }
+
+  const InstructionOperands* const operands_;
+  size_t operand_index_;  // the next register operand to read from frame
   const ShadowFrame& shadow_frame_;
-  size_t arg_index_;
 };
 
 // A convenience class that allows values to be written to a given shadow frame,
@@ -201,23 +191,19 @@
   size_t arg_index_;
 };
 
-template <bool is_range>
 bool MethodHandleInvoke(Thread* self,
                         ShadowFrame& shadow_frame,
                         Handle<mirror::MethodHandle> method_handle,
                         Handle<mirror::MethodType> callsite_type,
-                        const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                        uint32_t first_arg,
+                        const InstructionOperands* const args,
                         JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-template <bool is_range>
 bool MethodHandleInvokeExact(Thread* self,
                              ShadowFrame& shadow_frame,
                              Handle<mirror::MethodHandle> method_handle,
                              Handle<mirror::MethodType> callsite_type,
-                             const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                             uint32_t first_arg,
+                             const InstructionOperands* const args,
                              JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index f82bfbf..5757992 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -139,14 +139,12 @@
   DISALLOW_COPY_AND_ASSIGN(EmulatedStackFrameAccessor);
 };
 
-template <bool is_range>
 mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
     Thread* self,
     Handle<mirror::MethodType> caller_type,
     Handle<mirror::MethodType> callee_type,
     const ShadowFrame& caller_frame,
-    const uint32_t first_src_reg,
-    const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) {
+    const InstructionOperands* const operands) {
   StackHandleScope<6> hs(self);
 
   // Step 1: We must throw a WrongMethodTypeException if there's a mismatch in the
@@ -185,9 +183,9 @@
   }
 
   // Step 4 : Perform argument conversions (if required).
-  ShadowFrameGetter<is_range> getter(first_src_reg, arg, caller_frame);
+  ShadowFrameGetter getter(operands, caller_frame);
   EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
-  if (!PerformConversions<ShadowFrameGetter<is_range>, EmulatedStackFrameAccessor>(
+  if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>(
           self, caller_type, callee_type, &getter, &setter, num_method_params)) {
     return nullptr;
   }
@@ -289,21 +287,5 @@
   static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
 }
 
-// Explicit CreateFromShadowFrameAndArgs template function declarations.
-#define EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(_is_range)                         \
-  template REQUIRES_SHARED(Locks::mutator_lock_)                                           \
-  mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs<_is_range>( \
-    Thread* self,                                                                          \
-    Handle<mirror::MethodType> caller_type,                                                \
-    Handle<mirror::MethodType> callee_type,                                                \
-    const ShadowFrame& caller_frame,                                                       \
-    const uint32_t first_src_reg,                                                          \
-    const uint32_t (&arg)[Instruction::kMaxVarArgRegs])                                    \
-
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(true);
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(false);
-#undef EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL
-
-
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 76859ef..b6aa949 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -35,14 +35,12 @@
  public:
   // Creates an emulated stack frame whose type is |frame_type| from
   // a shadow frame.
-  template <bool is_range>
   static mirror::EmulatedStackFrame* CreateFromShadowFrameAndArgs(
       Thread* self,
       Handle<mirror::MethodType> args_type,
       Handle<mirror::MethodType> frame_type,
       const ShadowFrame& caller_frame,
-      const uint32_t first_src_reg,
-      const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) REQUIRES_SHARED(Locks::mutator_lock_);
+      const InstructionOperands* const operands) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Writes the contents of this emulated stack frame to the |callee_frame|
   // whose type is |callee_type|, starting at |first_dest_reg|.
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 4429ade..69bd46d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -193,7 +193,7 @@
 
   ret->PreLoad();
 
-  if (kIsVdexEnabled && !ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
+  if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
     return nullptr;
   }
 
@@ -233,7 +233,7 @@
                                       std::string* error_msg) {
   std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
 
-  if (kIsVdexEnabled && !ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
+  if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
     return nullptr;
   }
 
@@ -1275,7 +1275,7 @@
   std::string vdex_filename = GetVdexFilename(oat_filename);
 
   // Check that the files even exist, fast-fail.
-  if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) {
+  if (!OS::FileExists(vdex_filename.c_str())) {
     *error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str());
     return nullptr;
   } else if (!OS::FileExists(oat_filename.c_str())) {
@@ -1427,11 +1427,11 @@
 }
 
 const uint8_t* OatFile::DexBegin() const {
-  return kIsVdexEnabled ? vdex_->Begin() : Begin();
+  return vdex_->Begin();
 }
 
 const uint8_t* OatFile::DexEnd() const {
-  return kIsVdexEnabled ? vdex_->End() : End();
+  return vdex_->End();
 }
 
 ArrayRef<ArtMethod*> OatFile::GetBssMethods() const {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 378ce2c..cd18ce1 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, "
@@ -496,17 +475,10 @@
 
   // Verify the dex checksum.
   std::string error_msg;
-  if (kIsVdexEnabled) {
-    VdexFile* vdex = file.GetVdexFile();
-    if (!DexChecksumUpToDate(*vdex, &error_msg)) {
-      LOG(ERROR) << error_msg;
-      return kOatDexOutOfDate;
-    }
-  } else {
-    if (!DexChecksumUpToDate(file, &error_msg)) {
-      LOG(ERROR) << error_msg;
-      return kOatDexOutOfDate;
-    }
+  VdexFile* vdex = file.GetVdexFile();
+  if (!DexChecksumUpToDate(*vdex, &error_msg)) {
+    LOG(ERROR) << error_msg;
+    return kOatDexOutOfDate;
   }
 
   CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 65d01a4..a98da0f 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -351,58 +351,9 @@
   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) {
-  // This test case is only meaningful if vdex is enabled.
-  if (!kIsVdexEnabled) {
-    return;
-  }
-
   std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar";
   std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat";
 
@@ -446,10 +397,6 @@
 // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
 // file.
 TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) {
-  // This test case is only meaningful if vdex is enabled.
-  if (!kIsVdexEnabled) {
-    return;
-  }
   if (IsExecutedAsRoot()) {
     // We cannot simulate non writable locations when executed as root: b/38000545.
     LOG(ERROR) << "Test skipped because it's running as root";
@@ -668,11 +615,6 @@
 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
 // to the dex checksum, but no ODEX file.
 TEST_F(OatFileAssistantTest, VdexDexOutOfDate) {
-  // This test case is only meaningful if vdex is enabled.
-  if (!kIsVdexEnabled) {
-    return;
-  }
-
   std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
   std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
 
@@ -690,11 +632,6 @@
 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
 // is out of date and there is no corresponding ODEX file.
 TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
-  // This test case is only meaningful if vdex is enabled.
-  if (!kIsVdexEnabled) {
-    return;
-  }
-
   std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
   std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index ee35d9c..3071348 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -144,6 +144,9 @@
   return nullptr;
 }
 
+OatFileManager::OatFileManager()
+    : have_non_pic_oat_file_(false), only_use_system_oat_files_(false) {}
+
 OatFileManager::~OatFileManager() {
   // Explicitly clear oat_files_ since the OatFile destructor calls back into OatFileManager for
   // UnRegisterOatFileLocation.
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 1205773..dd6b7ba 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -45,7 +45,7 @@
 // pointers returned from functions are always valid.
 class OatFileManager {
  public:
-  OatFileManager() : have_non_pic_oat_file_(false), only_use_system_oat_files_(false) {}
+  OatFileManager();
   ~OatFileManager();
 
   // Add an oat file to the internal accounting, std::aborts if there already exists an oat file
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/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/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index b75becf..e2b8aa0 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -19,6 +19,7 @@
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
+#include "mirror/class.h"
 #include "oat_quick_method_header.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
diff --git a/test/626-checker-arm64-scratch-register/smali/Smali.smali b/test/626-checker-arm64-scratch-register/smali/Smali.smali
new file mode 100644
index 0000000..e6943cf
--- /dev/null
+++ b/test/626-checker-arm64-scratch-register/smali/Smali.smali
@@ -0,0 +1,2119 @@
+# 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.
+
+.class public LSmali;
+.super Ljava/lang/Object;
+.field b00:Z
+.field b01:Z
+.field b02:Z
+.field b03:Z
+.field b04:Z
+.field b05:Z
+.field b06:Z
+.field b07:Z
+.field b08:Z
+.field b09:Z
+.field b10:Z
+.field b11:Z
+.field b12:Z
+.field b13:Z
+.field b14:Z
+.field b15:Z
+.field b16:Z
+.field b17:Z
+.field b18:Z
+.field b19:Z
+.field b20:Z
+.field b21:Z
+.field b22:Z
+.field b23:Z
+.field b24:Z
+.field b25:Z
+.field b26:Z
+.field b27:Z
+.field b28:Z
+.field b29:Z
+.field b30:Z
+.field b31:Z
+.field b32:Z
+.field b33:Z
+.field b34:Z
+.field b35:Z
+.field b36:Z
+
+.field conditionA:Z
+.field conditionB:Z
+.field conditionC:Z
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+##  CHECK-START-ARM64: void Smali.test() register (after)
+##  CHECK: begin_block
+##  CHECK:   name "B0"
+##  CHECK:       <<This:l\d+>>  ParameterValue
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+##  CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+##  CHECK:                       If [<<CondB>>]
+##  CHECK:  end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlock>>"
+##  CHECK:                      ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)]
+##  CHECK: end_block
+
+##  CHECK-START-ARM64: void Smali.test() disassembly (after)
+##  CHECK: begin_block
+##  CHECK:   name "B0"
+##  CHECK:       <<This:l\d+>>  ParameterValue
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+##  CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+##  CHECK:                       If [<<CondB>>]
+##  CHECK:  end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlock>>"
+##  CHECK:                      ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
+##  CHECK:                        fmov d31, d2
+##  CHECK:                        ldr s2, [sp, #36]
+##  CHECK:                        ldr w16, [sp, #16]
+##  CHECK:                        str w16, [sp, #36]
+##  CHECK:                        str s14, [sp, #16]
+##  CHECK:                        ldr s14, [sp, #28]
+##  CHECK:                        str s1, [sp, #28]
+##  CHECK:                        ldr s1, [sp, #32]
+##  CHECK:                        str s31, [sp, #32]
+##  CHECK:                        ldr s31, [sp, #20]
+##  CHECK:                        str s31, [sp, #40]
+##  CHECK:                        str s12, [sp, #20]
+##  CHECK:                        fmov d12, d11
+##  CHECK:                        fmov d11, d10
+##  CHECK:                        fmov d10, d23
+##  CHECK:                        fmov d23, d22
+##  CHECK:                        fmov d22, d21
+##  CHECK:                        fmov d21, d20
+##  CHECK:                        fmov d20, d19
+##  CHECK:                        fmov d19, d18
+##  CHECK:                        fmov d18, d7
+##  CHECK:                        fmov d7, d6
+##  CHECK:                        fmov d6, d5
+##  CHECK:                        fmov d5, d4
+##  CHECK:                        fmov d4, d3
+##  CHECK:                        fmov d3, d13
+##  CHECK:                        ldr s13, [sp, #24]
+##  CHECK:                        str s3, [sp, #24]
+##  CHECK:                        ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100)
+##  CHECK: end_block
+.method public test()V
+    .registers 45
+
+    const-string v39, ""
+
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b17:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_367
+
+    const/16 v19, 0x0
+
+    :goto_c
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b16:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_36b
+
+    const/16 v18, 0x0
+
+    :goto_16
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b18:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_36f
+
+    const/16 v20, 0x0
+
+    :goto_20
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b19:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_373
+
+    const/16 v21, 0x0
+
+    :goto_2a
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b20:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_377
+
+    const/16 v22, 0x0
+
+    :goto_34
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b21:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_37b
+
+    const/16 v23, 0x0
+
+    :goto_3e
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b15:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_37f
+
+    const/16 v17, 0x0
+
+    :goto_48
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b00:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_383
+
+    const/4 v2, 0x0
+
+    :goto_51
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b22:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_387
+
+    const/16 v24, 0x0
+
+    :goto_5b
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b23:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_38b
+
+    const/16 v25, 0x0
+
+    :goto_65
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b24:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_38f
+
+    const/16 v26, 0x0
+
+    :goto_6f
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b25:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_393
+
+    const/16 v27, 0x0
+
+    :goto_79
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b26:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_397
+
+    const/16 v28, 0x0
+
+    :goto_83
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b27:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_39b
+
+    const/16 v29, 0x0
+
+    :goto_8d
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b29:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_39f
+
+    const/16 v31, 0x0
+
+    :goto_97
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b28:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3a3
+
+    const/16 v30, 0x0
+
+    :goto_a1
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b01:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3a7
+
+    const/4 v3, 0x0
+
+    :goto_aa
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b02:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3ab
+
+    const/4 v4, 0x0
+
+    :goto_b3
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b03:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3af
+
+    const/4 v5, 0x0
+
+    :goto_bc
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b04:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3b3
+
+    const/4 v6, 0x0
+
+    :goto_c5
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b05:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3b7
+
+    const/4 v7, 0x0
+
+    :goto_ce
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b07:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3bb
+
+    const/4 v9, 0x0
+
+    :goto_d7
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b06:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3bf
+
+    const/4 v8, 0x0
+
+    :goto_e0
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b30:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3c3
+
+    const/16 v32, 0x0
+
+    :goto_ea
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b31:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3c7
+
+    const/16 v33, 0x0
+
+    :goto_f4
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b32:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3cb
+
+    const/16 v34, 0x0
+
+    :goto_fe
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b33:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3cf
+
+    const/16 v35, 0x0
+
+    :goto_108
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b34:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3d3
+
+    const/16 v36, 0x0
+
+    :goto_112
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b36:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3d7
+
+    const/16 v38, 0x0
+
+    :goto_11c
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b35:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3db
+
+    const/16 v37, 0x0
+
+    :goto_126
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b08:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3df
+
+    const/4 v10, 0x0
+
+    :goto_12f
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b09:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3e3
+
+    const/4 v11, 0x0
+
+    :goto_138
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b10:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3e7
+
+    const/4 v12, 0x0
+
+    :goto_141
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b11:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3eb
+
+    const/4 v13, 0x0
+
+    :goto_14a
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b12:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3ef
+
+    const/4 v14, 0x0
+
+    :goto_153
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b14:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3f3
+
+    const/16 v16, 0x0
+
+    :goto_15d
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->b13:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_3f7
+
+    const/4 v15, 0x0
+
+    :goto_166
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->conditionA:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_202
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v18, v18, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v19, v19, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v20, v20, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v21, v21, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v22, v22, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v23, v23, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v17, v17, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v10, v10, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v11, v11, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v12, v12, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v13, v13, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v14, v14, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v32, v32, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v33, v33, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v34, v34, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v35, v35, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v36, v36, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v3, v3, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v4, v4, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v5, v5, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v6, v6, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v7, v7, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v25, v25, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v26, v26, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v27, v27, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v28, v28, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v29, v29, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v24, v24, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v2, v2, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v16, v16, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v15, v15, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v38, v38, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v37, v37, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v9, v9, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v8, v8, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v31, v31, v42
+
+    const/high16 v42, 0x447a0000    # 1000.0f
+
+    div-float v30, v30, v42
+
+    :cond_202
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->conditionB:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_29e
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v18, v18, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v19, v19, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v20, v20, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v21, v21, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v22, v22, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v23, v23, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v17, v17, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v10, v10, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v11, v11, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v12, v12, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v13, v13, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v14, v14, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v32, v32, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v33, v33, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v34, v34, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v35, v35, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v36, v36, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v3, v3, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v4, v4, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v5, v5, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v6, v6, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v7, v7, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v25, v25, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v26, v26, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v27, v27, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v28, v28, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v29, v29, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v24, v24, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v2, v2, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v16, v16, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v15, v15, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v38, v38, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v37, v37, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v9, v9, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v8, v8, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v31, v31, v42
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    div-float v30, v30, v42
+
+    :cond_29e
+    move-object/from16 v0, p0
+
+    iget-boolean v0, v0, LSmali;->conditionC:Z
+
+    move/from16 v42, v0
+
+    if-eqz v42, :cond_33a
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v18, v18, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v19, v19, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v20, v20, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v21, v21, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v22, v22, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v23, v23, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v17, v17, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v10, v10, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v11, v11, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v12, v12, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v13, v13, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v14, v14, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v32, v32, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v33, v33, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v34, v34, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v35, v35, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v36, v36, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v3, v3, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v4, v4, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v5, v5, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v6, v6, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v7, v7, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v25, v25, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v26, v26, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v27, v27, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v28, v28, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v29, v29, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v24, v24, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v2, v2, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v16, v16, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v15, v15, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v38, v38, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v37, v37, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v9, v9, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v8, v8, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v31, v31, v42
+
+    const/high16 v42, 0x41400000    # 12.0f
+
+    div-float v30, v30, v42
+
+    :cond_33a
+    const/16 v41, 0x0
+
+    const/high16 v42, 0x42c80000    # 100.0f
+
+    mul-float v42, v42, v41
+
+    invoke-static/range {v42 .. v42}, Ljava/lang/Math;->round(F)I
+
+    move-result v42
+
+    move/from16 v0, v42
+
+    int-to-float v0, v0
+
+    move/from16 v42, v0
+
+    const/high16 v43, 0x42c80000    # 100.0f
+
+    div-float v41, v42, v43
+
+    new-instance v42, Ljava/lang/StringBuilder;
+
+    invoke-direct/range {v42 .. v42}, Ljava/lang/StringBuilder;-><init>()V
+
+    move-object/from16 v0, v42
+
+    move/from16 v1, v41
+
+    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
+
+    move-result-object v42
+
+    move-object/from16 v0, v42
+
+    move-object/from16 v1, v39
+
+    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+    move-result-object v42
+
+    invoke-virtual/range {v42 .. v42}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+    move-result-object v40
+
+    return-void
+
+    :cond_367
+    const/high16 v19, 0x3f800000    # 1.0f
+
+    goto/16 :goto_c
+
+    :cond_36b
+    const/high16 v18, 0x3f800000    # 1.0f
+
+    goto/16 :goto_16
+
+    :cond_36f
+    const/high16 v20, 0x3f800000    # 1.0f
+
+    goto/16 :goto_20
+
+    :cond_373
+    const/high16 v21, 0x3f800000    # 1.0f
+
+    goto/16 :goto_2a
+
+    :cond_377
+    const/high16 v22, 0x3f800000    # 1.0f
+
+    goto/16 :goto_34
+
+    :cond_37b
+    const/high16 v23, 0x3f800000    # 1.0f
+
+    goto/16 :goto_3e
+
+    :cond_37f
+    const/high16 v17, 0x3f800000    # 1.0f
+
+    goto/16 :goto_48
+
+    :cond_383
+    const/high16 v2, 0x3f800000    # 1.0f
+
+    goto/16 :goto_51
+
+    :cond_387
+    const/high16 v24, 0x3f800000    # 1.0f
+
+    goto/16 :goto_5b
+
+    :cond_38b
+    const/high16 v25, 0x3f800000    # 1.0f
+
+    goto/16 :goto_65
+
+    :cond_38f
+    const/high16 v26, 0x3f800000    # 1.0f
+
+    goto/16 :goto_6f
+
+    :cond_393
+    const/high16 v27, 0x3f800000    # 1.0f
+
+    goto/16 :goto_79
+
+    :cond_397
+    const/high16 v28, 0x3f800000    # 1.0f
+
+    goto/16 :goto_83
+
+    :cond_39b
+    const/high16 v29, 0x3f800000    # 1.0f
+
+    goto/16 :goto_8d
+
+    :cond_39f
+    const/high16 v31, 0x3f800000    # 1.0f
+
+    goto/16 :goto_97
+
+    :cond_3a3
+    const/high16 v30, 0x3f800000    # 1.0f
+
+    goto/16 :goto_a1
+
+    :cond_3a7
+    const/high16 v3, 0x3f800000    # 1.0f
+
+    goto/16 :goto_aa
+
+    :cond_3ab
+    const/high16 v4, 0x3f800000    # 1.0f
+
+    goto/16 :goto_b3
+
+    :cond_3af
+    const/high16 v5, 0x3f800000    # 1.0f
+
+    goto/16 :goto_bc
+
+    :cond_3b3
+    const/high16 v6, 0x3f800000    # 1.0f
+
+    goto/16 :goto_c5
+
+    :cond_3b7
+    const/high16 v7, 0x3f800000    # 1.0f
+
+    goto/16 :goto_ce
+
+    :cond_3bb
+    const/high16 v9, 0x3f800000    # 1.0f
+
+    goto/16 :goto_d7
+
+    :cond_3bf
+    const/high16 v8, 0x3f800000    # 1.0f
+
+    goto/16 :goto_e0
+
+    :cond_3c3
+    const/high16 v32, 0x3f800000    # 1.0f
+
+    goto/16 :goto_ea
+
+    :cond_3c7
+    const/high16 v33, 0x3f800000    # 1.0f
+
+    goto/16 :goto_f4
+
+    :cond_3cb
+    const/high16 v34, 0x3f800000    # 1.0f
+
+    goto/16 :goto_fe
+
+    :cond_3cf
+    const/high16 v35, 0x3f800000    # 1.0f
+
+    goto/16 :goto_108
+
+    :cond_3d3
+    const/high16 v36, 0x3f800000    # 1.0f
+
+    goto/16 :goto_112
+
+    :cond_3d7
+    const/high16 v38, 0x3f800000    # 1.0f
+
+    goto/16 :goto_11c
+
+    :cond_3db
+    const/high16 v37, 0x3f800000    # 1.0f
+
+    goto/16 :goto_126
+
+    :cond_3df
+    const/high16 v10, 0x3f800000    # 1.0f
+
+    goto/16 :goto_12f
+
+    :cond_3e3
+    const/high16 v11, 0x3f800000    # 1.0f
+
+    goto/16 :goto_138
+
+    :cond_3e7
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    goto/16 :goto_141
+
+    :cond_3eb
+    const/high16 v13, 0x3f800000    # 1.0f
+
+    goto/16 :goto_14a
+
+    :cond_3ef
+    const/high16 v14, 0x3f800000    # 1.0f
+
+    goto/16 :goto_153
+
+    :cond_3f3
+    const/high16 v16, 0x3f800000    # 1.0f
+
+    goto/16 :goto_15d
+
+    :cond_3f7
+    const/high16 v15, 0x3f800000    # 1.0f
+
+    goto/16 :goto_166
+.end method
+
+##  CHECK-START-ARM64: void Smali.testD8() register (after)
+##  CHECK: begin_block
+##  CHECK:   name "B0"
+##  CHECK:       <<This:l\d+>>  ParameterValue
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:  successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+##  CHECK:       <<CondA:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionA
+##  CHECK:                       If [<<CondA>>]
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:   name "<<ThenBlockA>>"
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlockA>>"
+##  CHECK:                       ParallelMove moves:[d2->d0,40(sp)->d17,d20->d26,d19->d27,d27->d1,d26->d2,d14->d20,d13->d19,d17->d14,d0->d13]
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:  successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
+##  CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+##  CHECK:                       If [<<CondB>>]
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:   name "<<ThenBlockB>>"
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlockB>>"
+##  CHECK:                       ParallelMove moves:[#100->d13,16(sp)->d1,20(sp)->d2,28(sp)->d19,24(sp)->d20,36(sp)->d14,32(sp)->16(sp),d1->20(sp),d2->24(sp),d20->28(sp),d19->32(sp),d14->36(sp),d13->40(sp)]
+##  CHECK: end_block
+
+##  CHECK-START-ARM64: void Smali.testD8() disassembly (after)
+##  CHECK: begin_block
+##  CHECK:   name "B0"
+##  CHECK:       <<This:l\d+>>  ParameterValue
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:  successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+##  CHECK:       <<CondA:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionA
+##  CHECK:                       If [<<CondA>>]
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:   name "<<ThenBlockA>>"
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlockA>>"
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:  successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
+##  CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+##  CHECK:                       If [<<CondB>>]
+##  CHECK: end_block
+
+##  CHECK: begin_block
+##  CHECK:   name "<<ThenBlockB>>"
+##  CHECK: end_block
+##  CHECK: begin_block
+##  CHECK:   name "<<ElseBlockB>>"
+##  CHECK:                       ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
+##  CHECK:                         ldr w16, [sp, #32]
+##  CHECK:                         str s19, [sp, #32]
+##  CHECK:                         ldr s19, [sp, #28]
+##  CHECK:                         str s20, [sp, #28]
+##  CHECK:                         ldr s20, [sp, #24]
+##  CHECK:                         str s2, [sp, #24]
+##  CHECK:                         ldr s2, [sp, #20]
+##  CHECK:                         str s1, [sp, #20]
+##  CHECK:                         ldr s1, [sp, #16]
+##  CHECK:                         str w16, [sp, #16]
+##  CHECK:                         fmov d31, d14
+##  CHECK:                         ldr s14, [sp, #36]
+##  CHECK:                         str s31, [sp, #36]
+##  CHECK:                         str s13, [sp, #40]
+##  CHECK:                         ldr s13, pc+580 (addr 0x61c) (100)
+##  CHECK: end_block
+.method public testD8()V
+    .registers 47
+
+    move-object/from16 v0, p0
+
+    const-string v1, ""
+
+    iget-boolean v2, v0, LSmali;->b17:Z
+
+    if-eqz v2, :cond_a
+
+    const/4 v2, 0x0
+
+    goto :goto_c
+
+    :cond_a
+    const/high16 v2, 0x3f800000    # 1.0f
+
+    :goto_c
+    iget-boolean v5, v0, LSmali;->b16:Z
+
+    if-eqz v5, :cond_12
+
+    const/4 v5, 0x0
+
+    goto :goto_14
+
+    :cond_12
+    const/high16 v5, 0x3f800000    # 1.0f
+
+    :goto_14
+    iget-boolean v6, v0, LSmali;->b18:Z
+
+    if-eqz v6, :cond_1a
+
+    const/4 v6, 0x0
+
+    goto :goto_1c
+
+    :cond_1a
+    const/high16 v6, 0x3f800000    # 1.0f
+
+    :goto_1c
+    iget-boolean v7, v0, LSmali;->b19:Z
+
+    if-eqz v7, :cond_22
+
+    const/4 v7, 0x0
+
+    goto :goto_24
+
+    :cond_22
+    const/high16 v7, 0x3f800000    # 1.0f
+
+    :goto_24
+    iget-boolean v8, v0, LSmali;->b20:Z
+
+    if-eqz v8, :cond_2a
+
+    const/4 v8, 0x0
+
+    goto :goto_2c
+
+    :cond_2a
+    const/high16 v8, 0x3f800000    # 1.0f
+
+    :goto_2c
+    iget-boolean v9, v0, LSmali;->b21:Z
+
+    if-eqz v9, :cond_32
+
+    const/4 v9, 0x0
+
+    goto :goto_34
+
+    :cond_32
+    const/high16 v9, 0x3f800000    # 1.0f
+
+    :goto_34
+    iget-boolean v10, v0, LSmali;->b15:Z
+
+    if-eqz v10, :cond_3a
+
+    const/4 v10, 0x0
+
+    goto :goto_3c
+
+    :cond_3a
+    const/high16 v10, 0x3f800000    # 1.0f
+
+    :goto_3c
+    iget-boolean v11, v0, LSmali;->b00:Z
+
+    if-eqz v11, :cond_42
+
+    const/4 v11, 0x0
+
+    goto :goto_44
+
+    :cond_42
+    const/high16 v11, 0x3f800000    # 1.0f
+
+    :goto_44
+    iget-boolean v12, v0, LSmali;->b22:Z
+
+    if-eqz v12, :cond_4a
+
+    const/4 v12, 0x0
+
+    goto :goto_4c
+
+    :cond_4a
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    :goto_4c
+    iget-boolean v13, v0, LSmali;->b23:Z
+
+    if-eqz v13, :cond_52
+
+    const/4 v13, 0x0
+
+    goto :goto_54
+
+    :cond_52
+    const/high16 v13, 0x3f800000    # 1.0f
+
+    :goto_54
+    iget-boolean v14, v0, LSmali;->b24:Z
+
+    if-eqz v14, :cond_5a
+
+    const/4 v14, 0x0
+
+    goto :goto_5c
+
+    :cond_5a
+    const/high16 v14, 0x3f800000    # 1.0f
+
+    :goto_5c
+    iget-boolean v15, v0, LSmali;->b25:Z
+
+    if-eqz v15, :cond_62
+
+    const/4 v15, 0x0
+
+    goto :goto_64
+
+    :cond_62
+    const/high16 v15, 0x3f800000    # 1.0f
+
+    :goto_64
+    iget-boolean v3, v0, LSmali;->b26:Z
+
+    if-eqz v3, :cond_6a
+
+    const/4 v3, 0x0
+
+    goto :goto_6c
+
+    :cond_6a
+    const/high16 v3, 0x3f800000    # 1.0f
+
+    :goto_6c
+    iget-boolean v4, v0, LSmali;->b27:Z
+
+    if-eqz v4, :cond_72
+
+    const/4 v4, 0x0
+
+    goto :goto_74
+
+    :cond_72
+    const/high16 v4, 0x3f800000    # 1.0f
+
+    :goto_74
+    move-object/from16 v18, v1
+
+    iget-boolean v1, v0, LSmali;->b29:Z
+
+    if-eqz v1, :cond_7c
+
+    const/4 v1, 0x0
+
+    goto :goto_7e
+
+    :cond_7c
+    const/high16 v1, 0x3f800000    # 1.0f
+
+    :goto_7e
+    move/from16 v19, v1
+
+    iget-boolean v1, v0, LSmali;->b28:Z
+
+    if-eqz v1, :cond_86
+
+    const/4 v1, 0x0
+
+    goto :goto_88
+
+    :cond_86
+    const/high16 v1, 0x3f800000    # 1.0f
+
+    :goto_88
+    move/from16 v20, v1
+
+    iget-boolean v1, v0, LSmali;->b01:Z
+
+    if-eqz v1, :cond_90
+
+    const/4 v1, 0x0
+
+    goto :goto_92
+
+    :cond_90
+    const/high16 v1, 0x3f800000    # 1.0f
+
+    :goto_92
+    move/from16 v21, v11
+
+    iget-boolean v11, v0, LSmali;->b02:Z
+
+    if-eqz v11, :cond_9a
+
+    const/4 v11, 0x0
+
+    goto :goto_9c
+
+    :cond_9a
+    const/high16 v11, 0x3f800000    # 1.0f
+
+    :goto_9c
+    move/from16 v22, v12
+
+    iget-boolean v12, v0, LSmali;->b03:Z
+
+    if-eqz v12, :cond_a4
+
+    const/4 v12, 0x0
+
+    goto :goto_a6
+
+    :cond_a4
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    :goto_a6
+    move/from16 v23, v4
+
+    iget-boolean v4, v0, LSmali;->b04:Z
+
+    if-eqz v4, :cond_ae
+
+    const/4 v4, 0x0
+
+    goto :goto_b0
+
+    :cond_ae
+    const/high16 v4, 0x3f800000    # 1.0f
+
+    :goto_b0
+    move/from16 v24, v3
+
+    iget-boolean v3, v0, LSmali;->b05:Z
+
+    if-eqz v3, :cond_b8
+
+    const/4 v3, 0x0
+
+    goto :goto_ba
+
+    :cond_b8
+    const/high16 v3, 0x3f800000    # 1.0f
+
+    :goto_ba
+    move/from16 v25, v15
+
+    iget-boolean v15, v0, LSmali;->b07:Z
+
+    if-eqz v15, :cond_c2
+
+    const/4 v15, 0x0
+
+    goto :goto_c4
+
+    :cond_c2
+    const/high16 v15, 0x3f800000    # 1.0f
+
+    :goto_c4
+    move/from16 v26, v15
+
+    iget-boolean v15, v0, LSmali;->b06:Z
+
+    if-eqz v15, :cond_cc
+
+    const/4 v15, 0x0
+
+    goto :goto_ce
+
+    :cond_cc
+    const/high16 v15, 0x3f800000    # 1.0f
+
+    :goto_ce
+    move/from16 v27, v15
+
+    iget-boolean v15, v0, LSmali;->b30:Z
+
+    if-eqz v15, :cond_d6
+
+    const/4 v15, 0x0
+
+    goto :goto_d8
+
+    :cond_d6
+    const/high16 v15, 0x3f800000    # 1.0f
+
+    :goto_d8
+    move/from16 v28, v14
+
+    iget-boolean v14, v0, LSmali;->b31:Z
+
+    if-eqz v14, :cond_e0
+
+    const/4 v14, 0x0
+
+    goto :goto_e2
+
+    :cond_e0
+    const/high16 v14, 0x3f800000    # 1.0f
+
+    :goto_e2
+    move/from16 v29, v13
+
+    iget-boolean v13, v0, LSmali;->b32:Z
+
+    if-eqz v13, :cond_ea
+
+    const/4 v13, 0x0
+
+    goto :goto_ec
+
+    :cond_ea
+    const/high16 v13, 0x3f800000    # 1.0f
+
+    :goto_ec
+    move/from16 v30, v3
+
+    iget-boolean v3, v0, LSmali;->b33:Z
+
+    if-eqz v3, :cond_f4
+
+    const/4 v3, 0x0
+
+    goto :goto_f6
+
+    :cond_f4
+    const/high16 v3, 0x3f800000    # 1.0f
+
+    :goto_f6
+    move/from16 v31, v4
+
+    iget-boolean v4, v0, LSmali;->b34:Z
+
+    if-eqz v4, :cond_fe
+
+    const/4 v4, 0x0
+
+    goto :goto_100
+
+    :cond_fe
+    const/high16 v4, 0x3f800000    # 1.0f
+
+    :goto_100
+    move/from16 v32, v12
+
+    iget-boolean v12, v0, LSmali;->b36:Z
+
+    if-eqz v12, :cond_108
+
+    const/4 v12, 0x0
+
+    goto :goto_10a
+
+    :cond_108
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    :goto_10a
+    move/from16 v33, v12
+
+    iget-boolean v12, v0, LSmali;->b35:Z
+
+    if-eqz v12, :cond_112
+
+    const/4 v12, 0x0
+
+    goto :goto_114
+
+    :cond_112
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    :goto_114
+    move/from16 v34, v12
+
+    iget-boolean v12, v0, LSmali;->b08:Z
+
+    if-eqz v12, :cond_11c
+
+    const/4 v12, 0x0
+
+    goto :goto_11e
+
+    :cond_11c
+    const/high16 v12, 0x3f800000    # 1.0f
+
+    :goto_11e
+    move/from16 v35, v11
+
+    iget-boolean v11, v0, LSmali;->b09:Z
+
+    if-eqz v11, :cond_126
+
+    const/4 v11, 0x0
+
+    goto :goto_128
+
+    :cond_126
+    const/high16 v11, 0x3f800000    # 1.0f
+
+    :goto_128
+    move/from16 v36, v1
+
+    iget-boolean v1, v0, LSmali;->b10:Z
+
+    if-eqz v1, :cond_130
+
+    const/4 v1, 0x0
+
+    goto :goto_132
+
+    :cond_130
+    const/high16 v1, 0x3f800000    # 1.0f
+
+    :goto_132
+    move/from16 v37, v4
+
+    iget-boolean v4, v0, LSmali;->b11:Z
+
+    if-eqz v4, :cond_13a
+
+    const/4 v4, 0x0
+
+    goto :goto_13c
+
+    :cond_13a
+    const/high16 v4, 0x3f800000    # 1.0f
+
+    :goto_13c
+    move/from16 v38, v3
+
+    iget-boolean v3, v0, LSmali;->b12:Z
+
+    if-eqz v3, :cond_144
+
+    const/4 v3, 0x0
+
+    goto :goto_146
+
+    :cond_144
+    const/high16 v3, 0x3f800000    # 1.0f
+
+    :goto_146
+    move/from16 v39, v13
+
+    iget-boolean v13, v0, LSmali;->b14:Z
+
+    if-eqz v13, :cond_14e
+
+    const/4 v13, 0x0
+
+    goto :goto_150
+
+    :cond_14e
+    const/high16 v13, 0x3f800000    # 1.0f
+
+    :goto_150
+    move/from16 v40, v13
+
+    iget-boolean v13, v0, LSmali;->b13:Z
+
+    if-eqz v13, :cond_159
+
+    const/16 v16, 0x0
+
+    goto :goto_15b
+
+    :cond_159
+    const/high16 v16, 0x3f800000    # 1.0f
+
+    :goto_15b
+    move/from16 v13, v16
+
+    move/from16 v41, v13
+
+    iget-boolean v13, v0, LSmali;->conditionA:Z
+
+    if-eqz v13, :cond_1a2
+
+    const/high16 v13, 0x447a0000    # 1000.0f
+
+    div-float/2addr v5, v13
+
+    div-float/2addr v2, v13
+
+    div-float/2addr v6, v13
+
+    div-float/2addr v7, v13
+
+    div-float/2addr v8, v13
+
+    div-float/2addr v9, v13
+
+    div-float/2addr v10, v13
+
+    div-float/2addr v12, v13
+
+    div-float/2addr v11, v13
+
+    div-float/2addr v1, v13
+
+    div-float/2addr v4, v13
+
+    div-float/2addr v3, v13
+
+    div-float/2addr v15, v13
+
+    div-float/2addr v14, v13
+
+    div-float v16, v39, v13
+
+    div-float v38, v38, v13
+
+    div-float v37, v37, v13
+
+    div-float v36, v36, v13
+
+    div-float v35, v35, v13
+
+    div-float v32, v32, v13
+
+    div-float v31, v31, v13
+
+    div-float v30, v30, v13
+
+    div-float v29, v29, v13
+
+    div-float v28, v28, v13
+
+    div-float v25, v25, v13
+
+    div-float v24, v24, v13
+
+    div-float v23, v23, v13
+
+    div-float v22, v22, v13
+
+    div-float v21, v21, v13
+
+    div-float v39, v40, v13
+
+    div-float v40, v41, v13
+
+    div-float v33, v33, v13
+
+    div-float v34, v34, v13
+
+    div-float v26, v26, v13
+
+    div-float v27, v27, v13
+
+    div-float v19, v19, v13
+
+    div-float v13, v20, v13
+
+    goto :goto_1aa
+
+    :cond_1a2
+    move/from16 v13, v20
+
+    move/from16 v16, v39
+
+    move/from16 v39, v40
+
+    move/from16 v40, v41
+
+    :goto_1aa
+    move/from16 v42, v13
+
+    iget-boolean v13, v0, LSmali;->conditionB:Z
+
+    const/high16 v20, 0x42c80000    # 100.0f
+
+    if-eqz v13, :cond_1fd
+
+    div-float v5, v5, v20
+
+    div-float v2, v2, v20
+
+    div-float v6, v6, v20
+
+    div-float v7, v7, v20
+
+    div-float v8, v8, v20
+
+    div-float v9, v9, v20
+
+    div-float v10, v10, v20
+
+    div-float v12, v12, v20
+
+    div-float v11, v11, v20
+
+    div-float v1, v1, v20
+
+    div-float v4, v4, v20
+
+    div-float v3, v3, v20
+
+    div-float v15, v15, v20
+
+    div-float v14, v14, v20
+
+    div-float v16, v16, v20
+
+    div-float v38, v38, v20
+
+    div-float v37, v37, v20
+
+    div-float v36, v36, v20
+
+    div-float v35, v35, v20
+
+    div-float v32, v32, v20
+
+    div-float v31, v31, v20
+
+    div-float v30, v30, v20
+
+    div-float v29, v29, v20
+
+    div-float v28, v28, v20
+
+    div-float v25, v25, v20
+
+    div-float v24, v24, v20
+
+    div-float v23, v23, v20
+
+    div-float v22, v22, v20
+
+    div-float v21, v21, v20
+
+    div-float v39, v39, v20
+
+    div-float v40, v40, v20
+
+    div-float v33, v33, v20
+
+    div-float v34, v34, v20
+
+    div-float v26, v26, v20
+
+    div-float v27, v27, v20
+
+    div-float v19, v19, v20
+
+    div-float v13, v42, v20
+
+    goto :goto_1ff
+
+    :cond_1fd
+    move/from16 v13, v42
+
+    :goto_1ff
+    move/from16 v43, v13
+
+    iget-boolean v13, v0, LSmali;->conditionC:Z
+
+    if-eqz v13, :cond_244
+
+    const/high16 v13, 0x41400000    # 12.0f
+
+    div-float/2addr v5, v13
+
+    div-float/2addr v2, v13
+
+    div-float/2addr v6, v13
+
+    div-float/2addr v7, v13
+
+    div-float/2addr v8, v13
+
+    div-float/2addr v9, v13
+
+    div-float/2addr v10, v13
+
+    div-float/2addr v12, v13
+
+    div-float/2addr v11, v13
+
+    div-float/2addr v1, v13
+
+    div-float/2addr v4, v13
+
+    div-float/2addr v3, v13
+
+    div-float/2addr v15, v13
+
+    div-float/2addr v14, v13
+
+    div-float v16, v16, v13
+
+    div-float v38, v38, v13
+
+    div-float v37, v37, v13
+
+    div-float v36, v36, v13
+
+    div-float v35, v35, v13
+
+    div-float v32, v32, v13
+
+    div-float v31, v31, v13
+
+    div-float v30, v30, v13
+
+    div-float v29, v29, v13
+
+    div-float v28, v28, v13
+
+    div-float v25, v25, v13
+
+    div-float v24, v24, v13
+
+    div-float v23, v23, v13
+
+    div-float v22, v22, v13
+
+    div-float v21, v21, v13
+
+    div-float v39, v39, v13
+
+    div-float v40, v40, v13
+
+    div-float v33, v33, v13
+
+    div-float v34, v34, v13
+
+    div-float v26, v26, v13
+
+    div-float v27, v27, v13
+
+    div-float v19, v19, v13
+
+    div-float v13, v43, v13
+
+    goto :goto_246
+
+    :cond_244
+    move/from16 v13, v43
+
+    :goto_246
+    const/16 v17, 0x0
+
+    mul-float v0, v20, v17
+
+    invoke-static {v0}, Ljava/lang/Math;->round(F)I
+
+    move-result v0
+
+    int-to-float v0, v0
+
+    div-float v0, v0, v20
+
+    move/from16 v44, v1
+
+    new-instance v1, Ljava/lang/StringBuilder;
+
+    invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+
+    invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
+
+    move/from16 v45, v0
+
+    move-object/from16 v0, v18
+
+    invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+    move-result-object v1
+
+    return-void
+.end method
diff --git a/test/626-checker-arm64-scratch-register/src/Main.java b/test/626-checker-arm64-scratch-register/src/Main.java
index 1394917..cf94b87 100644
--- a/test/626-checker-arm64-scratch-register/src/Main.java
+++ b/test/626-checker-arm64-scratch-register/src/Main.java
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
 
 public class Main {
 
@@ -63,14 +65,17 @@
   /// CHECK:   name "B0"
   /// CHECK:       <<This:l\d+>>  ParameterValue
   /// CHECK: end_block
+
   /// CHECK: begin_block
-  /// CHECK:   successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+  /// CHECK:  successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+  /// CHECK:       <<CondA:z\d+>>  InstanceFieldGet [<<This>>] field_name:Main.conditionA
+  /// CHECK:                       If [<<CondA>>]
+  /// CHECK: end_block
+
+  /// CHECK: begin_block
+  /// CHECK:  successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
   /// CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Main.conditionB
   /// CHECK:                       If [<<CondB>>]
-  /// CHECK:  end_block
-  /// CHECK: begin_block
-  /// CHECK:   name "<<ElseBlock>>"
-  /// CHECK:                      ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)]
   /// CHECK: end_block
 
   /// CHECK-START-ARM64: void Main.test() disassembly (after)
@@ -82,39 +87,6 @@
   /// CHECK:   successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
   /// CHECK:       <<CondB:z\d+>>  InstanceFieldGet [<<This>>] field_name:Main.conditionB
   /// CHECK:                       If [<<CondB>>]
-  /// CHECK:  end_block
-  /// CHECK: begin_block
-  /// CHECK:   name "<<ElseBlock>>"
-  /// CHECK:                      ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
-  /// CHECK:                        fmov d31, d2
-  /// CHECK:                        ldr s2, [sp, #36]
-  /// CHECK:                        ldr w16, [sp, #16]
-  /// CHECK:                        str w16, [sp, #36]
-  /// CHECK:                        str s14, [sp, #16]
-  /// CHECK:                        ldr s14, [sp, #28]
-  /// CHECK:                        str s1, [sp, #28]
-  /// CHECK:                        ldr s1, [sp, #32]
-  /// CHECK:                        str s31, [sp, #32]
-  /// CHECK:                        ldr s31, [sp, #20]
-  /// CHECK:                        str s31, [sp, #40]
-  /// CHECK:                        str s12, [sp, #20]
-  /// CHECK:                        fmov d12, d11
-  /// CHECK:                        fmov d11, d10
-  /// CHECK:                        fmov d10, d23
-  /// CHECK:                        fmov d23, d22
-  /// CHECK:                        fmov d22, d21
-  /// CHECK:                        fmov d21, d20
-  /// CHECK:                        fmov d20, d19
-  /// CHECK:                        fmov d19, d18
-  /// CHECK:                        fmov d18, d7
-  /// CHECK:                        fmov d7, d6
-  /// CHECK:                        fmov d6, d5
-  /// CHECK:                        fmov d5, d4
-  /// CHECK:                        fmov d4, d3
-  /// CHECK:                        fmov d3, d13
-  /// CHECK:                        ldr s13, [sp, #24]
-  /// CHECK:                        str s3, [sp, #24]
-  /// CHECK:                        ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100)
   /// CHECK: end_block
 
   public void test() {
@@ -289,9 +261,20 @@
     String res = s + r;
   }
 
-  public static void main(String[] args) {
+  public static void main(String[] args) throws Exception {
     Main main = new Main();
     main.test();
+
+    Class<?> cl = Class.forName("Smali");
+    Constructor<?> cons = cl.getConstructor();
+    Object o = cons.newInstance();
+
+    Method test = cl.getMethod("test");
+    test.invoke(o);
+
+    Method testD8 = cl.getMethod("testD8");
+    testD8.invoke(o);
+
     System.out.println("passed");
   }
 }
diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java
index d365689..2188346 100644
--- a/test/651-checker-byte-simd-minmax/src/Main.java
+++ b/test/651-checker-byte-simd-minmax/src/Main.java
@@ -183,6 +183,13 @@
   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>  outer_loop:none
   /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>       outer_loop:none
+  //
+  /// CHECK-START-MIPS64: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]        loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>  outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>       outer_loop:none
   private static void doitMin100(byte[] x, byte[] y) {
     int min = Math.min(x.length, y.length);
     for (int i = 0; i < min; i++) {
diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java
index 72e8958..d92bdaf 100644
--- a/test/651-checker-char-simd-minmax/src/Main.java
+++ b/test/651-checker-char-simd-minmax/src/Main.java
@@ -97,6 +97,13 @@
   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>    outer_loop:none
   /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>         outer_loop:none
+  //
+  /// CHECK-START-MIPS64: void Main.doitMin100(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]        loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>    outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>         outer_loop:none
   private static void doitMin100(char[] x, char[] y) {
     int min = Math.min(x.length, y.length);
     for (int i = 0; i < min; i++) {
diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java
index d8c4d1e..91f2a2d 100644
--- a/test/651-checker-short-simd-minmax/src/Main.java
+++ b/test/651-checker-short-simd-minmax/src/Main.java
@@ -183,6 +183,13 @@
   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>   outer_loop:none
   /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>        outer_loop:none
+  //
+  /// CHECK-START-MIPS64: void Main.doitMin100(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<I100:i\d+>> IntConstant 100                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>]        loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop:B\d+>>   outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get>>,<<Repl>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>>        outer_loop:none
   private static void doitMin100(short[] x, short[] y) {
     int min = Math.min(x.length, y.length);
     for (int i = 0; i < min; i++) {
diff --git a/test/656-checker-simd-opt/src/Main.java b/test/656-checker-simd-opt/src/Main.java
index 39a126f..31d28e8 100644
--- a/test/656-checker-simd-opt/src/Main.java
+++ b/test/656-checker-simd-opt/src/Main.java
@@ -114,6 +114,19 @@
   /// CHECK-DAG: <<Phi2:d\d+>>  Phi [<<Set>>,{{d\d+}}]       loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                VecAdd [<<Phi2>>,<<Rep>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                Add [<<Phi1>>,<<L2>>]        loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.longInductionReduction(long[]) loop_optimization (after)
+  /// CHECK-DAG: <<L0:j\d+>>    LongConstant 0               loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1               loop:none
+  /// CHECK-DAG: <<L2:j\d+>>    LongConstant 2               loop:none
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]   loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Get>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>   VecSetScalars [<<L1>>]       loop:none
+  /// CHECK-DAG: <<Phi1:j\d+>>  Phi [<<L0>>,{{j\d+}}]        loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>  Phi [<<Set>>,{{d\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                VecAdd [<<Phi2>>,<<Rep>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi1>>,<<L2>>]        loop:<<Loop>>      outer_loop:none
   static long longInductionReduction(long[] y) {
     long x = 1;
     for (long i = 0; i < 10; i++) {
@@ -141,6 +154,17 @@
   /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
+  /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                       loop:none
+  /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
+  /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]          loop:none
+  /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<Get>>]            loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
   static void intVectorLongInvariant(int[] x, long[] y) {
     for (int i = 0; i < 100; i++) {
       x[i] = (int) y[0];
@@ -170,6 +194,18 @@
   /// CHECK-DAG: <<Add:d\d+>>   VecAdd [<<Load>>,<<Rep>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
+  /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
+  /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1                      loop:none
+  /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<L1>>]             loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>  VecLoad [{{l\d+}},<<Phi>>]          loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add:d\d+>>   VecAdd [<<Load>>,<<Rep>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
   static void longCanBeDoneWithInt(int[] x, int[] y) {
     for (int i = 0; i < 100; i++) {
       x[i] = (int) (y[i] + 1L);
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
index 72d1c24..877d718 100644
--- a/test/660-checker-simd-sad-byte/src/Main.java
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -109,6 +109,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
   private static int sadByte2Int(byte[] b1, byte[] b2) {
     int min_length = Math.min(b1.length, b2.length);
     int sad = 0;
@@ -140,6 +151,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
   private static int sadByte2IntAlt(byte[] b1, byte[] b2) {
     int min_length = Math.min(b1.length, b2.length);
     int sad = 0;
@@ -173,6 +195,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
   private static int sadByte2IntAlt2(byte[] b1, byte[] b2) {
     int min_length = Math.min(b1.length, b2.length);
     int sad = 0;
@@ -212,6 +245,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
   private static long sadByte2Long(byte[] b1, byte[] b2) {
     int min_length = Math.min(b1.length, b2.length);
     long sad = 0;
@@ -249,6 +294,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16                 loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons16>>]      loop:<<Loop>>      outer_loop:none
   private static long sadByte2LongAt1(byte[] b1, byte[] b2) {
     int min_length = Math.min(b1.length, b2.length);
     long sad = 1;  // starts at 1
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
index 2535d49..ba22614 100644
--- a/test/660-checker-simd-sad-char/src/Main.java
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -68,7 +68,7 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadChar2Int(char[], char[]) loop_optimization (after)
+  /// CHECK-START: int Main.sadChar2Int(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static int sadChar2Int(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
@@ -91,7 +91,7 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (after)
+  /// CHECK-START: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static int sadChar2IntAlt(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
@@ -116,7 +116,7 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (after)
+  /// CHECK-START: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static int sadChar2IntAlt2(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
@@ -146,7 +146,7 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: long Main.sadChar2Long(char[], char[]) loop_optimization (after)
+  /// CHECK-START: long Main.sadChar2Long(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static long sadChar2Long(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
@@ -174,7 +174,7 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (after)
+  /// CHECK-START: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static long sadChar2LongAt1(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index 388bfba..d7d5a95 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -48,6 +48,15 @@
   /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<I>>,<<Cons4>>]                      loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                              loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [{{i\d+}}]                   loop:none
+  /// CHECK-DAG: <<Phi:d\d+>>    Phi [<<Set>>,{{d\d+}}]                     loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Ld1:d\d+>>    VecLoad [{{l\d+}},<<I:i\d+>>]              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<I>>,<<Cons4>>]                      loop:<<Loop>> outer_loop:none
   private static int sadInt2Int(int[] x, int[] y) {
     int min_length = Math.min(x.length, y.length);
     int sad = 0;
@@ -72,10 +81,7 @@
   //
   // No ABS? No SAD!
   //
-  /// CHECK-START-ARM: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
-  /// CHECK-NOT: VecSADAccumulate
-  //
-  /// CHECK-START-ARM64: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
+  /// CHECK-START: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static int sadInt2IntAlt(int[] x, int[] y) {
     int min_length = Math.min(x.length, y.length);
@@ -117,6 +123,15 @@
   /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<I>>,<<Cons4>>]                      loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                              loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [{{i\d+}}]                   loop:none
+  /// CHECK-DAG: <<Phi:d\d+>>    Phi [<<Set>>,{{d\d+}}]                     loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Ld1:d\d+>>    VecLoad [{{l\d+}},<<I:i\d+>>]              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<I>>,<<Cons4>>]                      loop:<<Loop>> outer_loop:none
   private static int sadInt2IntAlt2(int[] x, int[] y) {
     int min_length = Math.min(x.length, y.length);
     int sad = 0;
@@ -156,6 +171,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
   private static long sadInt2Long(int[] x, int[] y) {
     int min_length = Math.min(x.length, y.length);
     long sad = 0;
@@ -193,6 +220,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
   private static long sadInt2LongAt1(int[] x, int[] y) {
     int min_length = Math.min(x.length, y.length);
     long sad = 1;  // starts at 1
diff --git a/test/660-checker-simd-sad-long/src/Main.java b/test/660-checker-simd-sad-long/src/Main.java
index 06f62bd..d080e0c 100644
--- a/test/660-checker-simd-sad-long/src/Main.java
+++ b/test/660-checker-simd-sad-long/src/Main.java
@@ -43,6 +43,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
   private static long sadLong2Long(long[] x, long[] y) {
     int min_length = Math.min(x.length, y.length);
     long sad = 0;
@@ -105,6 +117,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
   private static long sadLong2LongAlt2(long[] x, long[] y) {
     int min_length = Math.min(x.length, y.length);
     long sad = 0;
@@ -142,6 +166,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
   private static long sadLong2LongAt1(long[] x, long[] y) {
     int min_length = Math.min(x.length, y.length);
     long sad = 1;  // starts at 1
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
index d94308e..4ab6682 100644
--- a/test/660-checker-simd-sad-short/src/Main.java
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -76,6 +76,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2Int(short[] s1, short[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -107,6 +118,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntAlt(short[] s1, short[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -140,6 +162,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntAlt2(short[] s1, short[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -179,6 +212,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static long sadShort2Long(short[] s1, short[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 0;
@@ -216,6 +261,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static long sadShort2LongAt1(short[] s1, short[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 1;  // starts at 1
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
index 708f3aa..331f5ce 100644
--- a/test/660-checker-simd-sad-short2/src/Main.java
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -94,6 +94,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadCastedChar2Int(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -144,6 +155,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadCastedChar2IntAlt(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -196,6 +218,17 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadCastedChar2IntAlt2(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
@@ -254,6 +287,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static long sadCastedChar2Long(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 0;
@@ -310,6 +355,18 @@
   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static long sadCastedChar2LongAt1(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 1;  // starts at 1
diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java
index c8850b4..ecda884 100644
--- a/test/660-checker-simd-sad-short3/src/Main.java
+++ b/test/660-checker-simd-sad-short3/src/Main.java
@@ -44,6 +44,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Param:s\d+>>  ParameterValue                 loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<Param>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntParamRight(short[] s, short param) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
@@ -75,6 +87,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Param:s\d+>>  ParameterValue                 loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<Param>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntParamLeft(short[] s, short param) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
@@ -106,6 +130,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntConstRight(short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 32767              loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<ConsI>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntConstRight(short[] s) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
@@ -137,6 +173,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 32767              loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<ConsI>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntConstLeft(short[] s) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
@@ -168,6 +216,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [{{i\d+}}]      loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<Conv>>]  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
   private static int sadShort2IntInvariantRight(short[] s, int val) {
     int sad = 0;
     short x = (short) (val + 1);
@@ -199,6 +259,17 @@
   /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Conv:s\d+>>   TypeConversion [{{i\d+}}]      loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<Conv>>]  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
   private static int sadShort2IntInvariantLeft(short[] s, int val) {
     int sad = 0;
     short x = (short) (val + 1);
@@ -233,6 +304,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:d\d+>>    VecAdd [<<Load>>,<<Rep>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 110                loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<ConsI>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add:d\d+>>    VecAdd [<<Load>>,<<Rep>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
   private static int sadShort2IntCastedExprRight(short[] s) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
@@ -267,6 +350,18 @@
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Add:d\d+>>    VecAdd [<<Load>>,<<Rep>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
+  //
+  /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsI:i\d+>>  IntConstant 110                loop:none
+  /// CHECK-DAG: <<Rep:d\d+>>    VecReplicateScalar [<<ConsI>>] loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Add:d\d+>>    VecAdd [<<Load>>,<<Rep>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
   private static int sadShort2IntCastedExprLeft(short[] s) {
     int sad = 0;
     for (int i = 0; i < s.length; i++) {
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/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 2b940ab..df497c1 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -26,6 +26,7 @@
 #include "jit/profiling_info.h"
 #include "mirror/class-inl.h"
 #include "nativehelper/ScopedUtfChars.h"
+#include "oat_file.h"
 #include "oat_quick_method_header.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
diff --git a/tools/ahat/etc/test-dump.pro b/tools/ahat/etc/test-dump.pro
index 284e4b8..296d411 100644
--- a/tools/ahat/etc/test-dump.pro
+++ b/tools/ahat/etc/test-dump.pro
@@ -3,3 +3,12 @@
   public static void main(java.lang.String[]);
 }
 
+-keep public class SuperDumpedStuff {
+  public void allocateObjectAtUnObfSuperSite();
+}
+
+# Produce useful obfuscated stack traces so we can test useful deobfuscation
+# of stack traces.
+-renamesourcefileattribute SourceFile
+-keepattributes SourceFile,LineNumberTable
+
diff --git a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
index 131bbf3..32bb209 100644
--- a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
+++ b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
@@ -88,12 +88,10 @@
       String key = obfuscatedMethodName + clearSignature;
       FrameData frame = mFrames.get(key);
       if (frame == null) {
-        return new Frame(obfuscatedMethodName, clearSignature,
-            obfuscatedFilename, obfuscatedLine);
+        frame = new FrameData(obfuscatedMethodName, 0);
       }
       return new Frame(frame.clearMethodName, clearSignature,
-          getFileName(clearClassName, frame.clearMethodName),
-          obfuscatedLine - frame.lineDelta);
+          getFileName(clearClassName), obfuscatedLine - frame.lineDelta);
     }
   }
 
@@ -313,15 +311,10 @@
     return builder.toString();
   }
 
-  // Return a file name for the given clear class name and method.
-  private static String getFileName(String clearClass, String method) {
-    int dot = method.lastIndexOf('.');
-    if (dot != -1) {
-      clearClass = method.substring(0, dot);
-    }
-
+  // Return a file name for the given clear class name.
+  private static String getFileName(String clearClass) {
     String filename = clearClass;
-    dot = filename.lastIndexOf('.');
+    int dot = filename.lastIndexOf('.');
     if (dot != -1) {
       filename = filename.substring(dot + 1);
     }
diff --git a/tools/ahat/src/test-dump/DumpedStuff.java b/tools/ahat/src/test-dump/DumpedStuff.java
new file mode 100644
index 0000000..98ead07
--- /dev/null
+++ b/tools/ahat/src/test-dump/DumpedStuff.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import libcore.util.NativeAllocationRegistry;
+
+// We take a heap dump that includes a single instance of this
+// DumpedStuff class. Objects stored as fields in this class can be easily
+// found in the hprof dump by searching for the instance of the DumpedStuff
+// class and reading the desired field.
+public class DumpedStuff extends SuperDumpedStuff {
+  private void allocateObjectAtKnownSite() {
+    objectAllocatedAtKnownSite = new Object();
+    allocateObjectAtKnownSubSite();
+    allocateObjectAtObfSuperSite();
+    allocateObjectAtUnObfSuperSite();
+    allocateObjectAtOverriddenSite();
+  }
+
+  private void allocateObjectAtKnownSubSite() {
+    objectAllocatedAtKnownSubSite = new Object();
+  }
+
+  public void allocateObjectAtOverriddenSite() {
+    objectAllocatedAtOverriddenSite = new Object();
+  }
+
+  DumpedStuff(boolean baseline) {
+    allocateObjectAtKnownSite();
+
+    int n = baseline ? 400000 : 1000000;
+    bigArray = new byte[n];
+    for (int i = 0; i < n; i++) {
+      bigArray[i] = (byte)((i * i) & 0xFF);
+    }
+
+    // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
+    NativeAllocationRegistry registry = new NativeAllocationRegistry(
+        Main.class.getClassLoader(), 0x12345, 50000);
+    registry.registerNativeAllocation(anObject, 0xABCDABCD);
+
+    {
+      Object object = new Object();
+      aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object)));
+      aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object));
+    }
+
+    addedObject = baseline ? null : new AddedObject();
+    removedObject = baseline ? new RemovedObject() : null;
+    modifiedObject = new ModifiedObject();
+    modifiedObject.value = baseline ? 5 : 8;
+    modifiedObject.modifiedRefField = baseline ? "A1" : "A2";
+    modifiedObject.unmodifiedRefField = "B";
+    modifiedStaticField = baseline ? "C1" : "C2";
+    modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0};
+
+    // Deep matching dominator trees shouldn't smash the stack when we try
+    // to diff them. Make some deep dominator trees to help test it.
+    for (int i = 0; i < 10000; i++) {
+      StackSmasher smasher = new StackSmasher();
+      smasher.child = stackSmasher;
+      stackSmasher = smasher;
+
+      if (!baseline) {
+        smasher = new StackSmasher();
+        smasher.child = stackSmasherAdded;
+        stackSmasherAdded = smasher;
+      }
+    }
+
+    gcPathArray[2].right.left = gcPathArray[2].left.right;
+  }
+
+  public static class ObjectTree {
+    public ObjectTree left;
+    public ObjectTree right;
+
+    public ObjectTree(ObjectTree left, ObjectTree right) {
+      this.left = left;
+      this.right = right;
+    }
+  }
+
+  public static class AddedObject {
+  }
+
+  public static class RemovedObject {
+  }
+
+  public static class UnchangedObject {
+  }
+
+  public static class ModifiedObject {
+    public int value;
+    public String modifiedRefField;
+    public String unmodifiedRefField;
+  }
+
+  public static class StackSmasher {
+    public StackSmasher child;
+  }
+
+  public static class Reference {
+    public Object referent;
+
+    public Reference(Object referent) {
+      this.referent = referent;
+    }
+  }
+
+  public String basicString = "hello, world";
+  public String nonAscii = "Sigma (Ʃ) is not ASCII";
+  public String embeddedZero = "embedded\0...";  // Non-ASCII for string compression purposes.
+  public char[] charArray = "char thing".toCharArray();
+  public String nullString = null;
+  public Object anObject = new Object();
+  public Reference aReference = new Reference(anObject);
+  public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
+  public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
+  public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
+  public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
+  public SoftReference aSoftReference = new SoftReference(new Object());
+  public byte[] bigArray;
+  public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
+    new ObjectTree(
+        new ObjectTree(null, new ObjectTree(null, null)),
+        new ObjectTree(null, null)),
+    null};
+  public Reference aLongStrongPathToSamplePathObject;
+  public WeakReference aShortWeakPathToSamplePathObject;
+  public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class);
+  public SoftReference aWeakChain = new SoftReference(new Reference(new Reference(new Object())));
+  public Object[] basicStringRef;
+  public AddedObject addedObject;
+  public UnchangedObject unchangedObject = new UnchangedObject();
+  public RemovedObject removedObject;
+  public ModifiedObject modifiedObject;
+  public StackSmasher stackSmasher;
+  public StackSmasher stackSmasherAdded;
+  public static String modifiedStaticField;
+  public int[] modifiedArray;
+  public Object objectAllocatedAtKnownSite;
+  public Object objectAllocatedAtKnownSubSite;
+}
diff --git a/tools/ahat/src/test-dump/Main.java b/tools/ahat/src/test-dump/Main.java
index 079be7d..de36748 100644
--- a/tools/ahat/src/test-dump/Main.java
+++ b/tools/ahat/src/test-dump/Main.java
@@ -16,11 +16,6 @@
 
 import dalvik.system.VMDebug;
 import java.io.IOException;
-import java.lang.ref.PhantomReference;
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
-import libcore.util.NativeAllocationRegistry;
 import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
 
 /**
@@ -31,138 +26,6 @@
   // collected before we take the heap dump.
   public static DumpedStuff stuff;
 
-  public static class ObjectTree {
-    public ObjectTree left;
-    public ObjectTree right;
-
-    public ObjectTree(ObjectTree left, ObjectTree right) {
-      this.left = left;
-      this.right = right;
-    }
-  }
-
-  public static class AddedObject {
-  }
-
-  public static class RemovedObject {
-  }
-
-  public static class UnchangedObject {
-  }
-
-  public static class ModifiedObject {
-    public int value;
-    public String modifiedRefField;
-    public String unmodifiedRefField;
-  }
-
-  public static class StackSmasher {
-    public StackSmasher child;
-  }
-
-  public static class Reference {
-    public Object referent;
-
-    public Reference(Object referent) {
-      this.referent = referent;
-    }
-  }
-
-  // We will take a heap dump that includes a single instance of this
-  // DumpedStuff class. Objects stored as fields in this class can be easily
-  // found in the hprof dump by searching for the instance of the DumpedStuff
-  // class and reading the desired field.
-  public static class DumpedStuff {
-    public String basicString = "hello, world";
-    public String nonAscii = "Sigma (Ʃ) is not ASCII";
-    public String embeddedZero = "embedded\0...";  // Non-ASCII for string compression purposes.
-    public char[] charArray = "char thing".toCharArray();
-    public String nullString = null;
-    public Object anObject = new Object();
-    public Reference aReference = new Reference(anObject);
-    public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
-    public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
-    public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
-    public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
-    public SoftReference aSoftReference = new SoftReference(new Object());
-    public byte[] bigArray;
-    public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
-      new ObjectTree(
-          new ObjectTree(null, new ObjectTree(null, null)),
-          new ObjectTree(null, null)),
-      null};
-    public Reference aLongStrongPathToSamplePathObject;
-    public WeakReference aShortWeakPathToSamplePathObject;
-    public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class);
-    public SoftReference aWeakChain = new SoftReference(new Reference(new Reference(new Object())));
-    public Object[] basicStringRef;
-    public AddedObject addedObject;
-    public UnchangedObject unchangedObject = new UnchangedObject();
-    public RemovedObject removedObject;
-    public ModifiedObject modifiedObject;
-    public StackSmasher stackSmasher;
-    public StackSmasher stackSmasherAdded;
-    public static String modifiedStaticField;
-    public int[] modifiedArray;
-    public Object objectAllocatedAtKnownSite1;
-    public Object objectAllocatedAtKnownSite2;
-
-    private void allocateObjectAtKnownSite1() {
-      objectAllocatedAtKnownSite1 = new Object();
-      allocateObjectAtKnownSite2();
-    }
-
-    private void allocateObjectAtKnownSite2() {
-      objectAllocatedAtKnownSite2 = new Object();
-    }
-
-    DumpedStuff(boolean baseline) {
-      int n = baseline ? 400000 : 1000000;
-      bigArray = new byte[n];
-      for (int i = 0; i < n; i++) {
-        bigArray[i] = (byte)((i * i) & 0xFF);
-      }
-
-      // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
-      NativeAllocationRegistry registry = new NativeAllocationRegistry(
-          Main.class.getClassLoader(), 0x12345, 50000);
-      registry.registerNativeAllocation(anObject, 0xABCDABCD);
-
-      {
-        Object object = new Object();
-        aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object)));
-        aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object));
-      }
-
-      addedObject = baseline ? null : new AddedObject();
-      removedObject = baseline ? new RemovedObject() : null;
-      modifiedObject = new ModifiedObject();
-      modifiedObject.value = baseline ? 5 : 8;
-      modifiedObject.modifiedRefField = baseline ? "A1" : "A2";
-      modifiedObject.unmodifiedRefField = "B";
-      modifiedStaticField = baseline ? "C1" : "C2";
-      modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0};
-
-      allocateObjectAtKnownSite1();
-
-      // Deep matching dominator trees shouldn't smash the stack when we try
-      // to diff them. Make some deep dominator trees to help test it.
-      for (int i = 0; i < 10000; i++) {
-        StackSmasher smasher = new StackSmasher();
-        smasher.child = stackSmasher;
-        stackSmasher = smasher;
-
-        if (!baseline) {
-          smasher = new StackSmasher();
-          smasher.child = stackSmasherAdded;
-          stackSmasherAdded = smasher;
-        }
-      }
-
-      gcPathArray[2].right.left = gcPathArray[2].left.right;
-    }
-  }
-
   public static void main(String[] args) throws IOException {
     if (args.length < 1) {
       System.err.println("no output file specified");
diff --git a/tools/ahat/src/test-dump/SuperDumpedStuff.java b/tools/ahat/src/test-dump/SuperDumpedStuff.java
new file mode 100644
index 0000000..5ec62ae
--- /dev/null
+++ b/tools/ahat/src/test-dump/SuperDumpedStuff.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// A super class for DumpedStuff to test deobfuscation of methods inherited
+// from the super class.
+public class SuperDumpedStuff {
+
+  public void allocateObjectAtObfSuperSite() {
+    objectAllocatedAtObfSuperSite = new Object();
+  }
+
+  public void allocateObjectAtUnObfSuperSite() {
+    objectAllocatedAtUnObfSuperSite = new Object();
+  }
+
+  public void allocateObjectAtOverriddenSite() {
+    objectAllocatedAtOverriddenSite = new Object();
+  }
+
+  public Object objectAllocatedAtObfSuperSite;
+  public Object objectAllocatedAtUnObfSuperSite;
+  public Object objectAllocatedAtOverriddenSite;
+}
diff --git a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
index ad40f45..02976b5 100644
--- a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
+++ b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
@@ -45,7 +45,6 @@
     + "    64:66:class.with.only.Fields methodWithObfRes() -> n\n"
     + "    80:80:void lineObfuscatedMethod():8:8 -> o\n"
     + "    90:90:void lineObfuscatedMethod2():9 -> p\n"
-    + "    120:121:void method.from.a.Superclass.supermethod() -> q\n"
     ;
 
   @Test
@@ -160,12 +159,10 @@
     assertEquals("Methods.java", frame.filename);
     assertEquals(13, frame.line);
 
-    frame = map.getFrame("class.with.Methods", "q", "()V", "SourceFile.java", 120);
-    // TODO: Should this be "supermethod", instead of
-    // "method.from.a.Superclass.supermethod"?
-    assertEquals("method.from.a.Superclass.supermethod", frame.method);
-    assertEquals("()V", frame.signature);
-    assertEquals("Superclass.java", frame.filename);
-    assertEquals(120, frame.line);
+    // Some methods may not have been obfuscated. We should still be able
+    // to compute the filename properly.
+    frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName",
+        "()V", "SourceFile.java", 0);
+    assertEquals("Methods.java", frame.filename);
   }
 }
diff --git a/tools/ahat/src/test/com/android/ahat/SiteTest.java b/tools/ahat/src/test/com/android/ahat/SiteTest.java
index dc0fe08..0443d7f 100644
--- a/tools/ahat/src/test/com/android/ahat/SiteTest.java
+++ b/tools/ahat/src/test/com/android/ahat/SiteTest.java
@@ -23,6 +23,7 @@
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 
 public class SiteTest {
@@ -31,36 +32,54 @@
     TestDump dump = TestDump.getTestDump();
     AhatSnapshot snapshot = dump.getAhatSnapshot();
 
-    AhatInstance obj1 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite1");
-    AhatInstance obj2 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite2");
-    Site s2 = obj2.getSite();
-    Site s1b = s2.getParent();
-    Site s1a = obj1.getSite();
-    Site s = s1a.getParent();
+    AhatInstance oKnownSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite");
+    Site sKnownSite = oKnownSite.getSite();
+    assertEquals("DumpedStuff.java", sKnownSite.getFilename());
+    assertEquals("allocateObjectAtKnownSite", sKnownSite.getMethodName());
+    assertEquals(29, sKnownSite.getLineNumber());
+    assertSame(sKnownSite, snapshot.getSite(sKnownSite.getId()));
 
-    // TODO: The following commented out assertion fails due to a problem with
-    //       proguard deobfuscation. That bug should be fixed.
-    // assertEquals("Main.java", s.getFilename());
+    AhatInstance oKnownSubSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSubSite");
+    Site sKnownSubSite = oKnownSubSite.getSite();
+    assertEquals("DumpedStuff.java", sKnownSubSite.getFilename());
+    assertEquals("allocateObjectAtKnownSubSite", sKnownSubSite.getMethodName());
+    assertEquals(37, sKnownSubSite.getLineNumber());
+    assertSame(sKnownSubSite, snapshot.getSite(sKnownSubSite.getId()));
 
-    assertEquals("Main.java", s1a.getFilename());
-    assertEquals("Main.java", s1b.getFilename());
-    assertEquals("Main.java", s2.getFilename());
+    Site sKnownSubSiteParent = sKnownSubSite.getParent();
+    assertEquals("DumpedStuff.java", sKnownSubSiteParent.getFilename());
+    assertEquals("allocateObjectAtKnownSite", sKnownSubSiteParent.getMethodName());
+    assertEquals(30, sKnownSubSiteParent.getLineNumber());
+    assertSame(sKnownSubSiteParent, snapshot.getSite(sKnownSubSiteParent.getId()));
 
-    assertEquals("allocateObjectAtKnownSite1", s1a.getMethodName());
-    assertEquals("allocateObjectAtKnownSite1", s1b.getMethodName());
-    assertEquals("allocateObjectAtKnownSite2", s2.getMethodName());
+    assertNotSame(sKnownSite, sKnownSubSiteParent);
+    assertSame(sKnownSite.getParent(), sKnownSubSiteParent.getParent());
 
-    // TODO: The following commented out assertion fails due to a problem with
-    //       stack frame line numbers - we don't get different line numbers
-    //       for the different sites, so they are indistiguishable. The
-    //       problem with line numbers should be understood and fixed.
-    // assertNotSame(s1a, s1b);
+    Site sKnownSiteParent = sKnownSite.getParent();
+    assertEquals("DumpedStuff.java", sKnownSiteParent.getFilename());
+    assertEquals("<init>", sKnownSiteParent.getMethodName());
+    assertEquals(45, sKnownSiteParent.getLineNumber());
+    assertSame(sKnownSiteParent, snapshot.getSite(sKnownSiteParent.getId()));
 
-    assertSame(s1a.getParent(), s1b.getParent());
+    AhatInstance oObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtObfSuperSite");
+    Site sObfSuperSite = oObfSuperSite.getSite();
+    assertEquals("SuperDumpedStuff.java", sObfSuperSite.getFilename());
+    assertEquals("allocateObjectAtObfSuperSite", sObfSuperSite.getMethodName());
+    assertEquals(22, sObfSuperSite.getLineNumber());
+    assertSame(sObfSuperSite, snapshot.getSite(sObfSuperSite.getId()));
 
-    assertSame(s, snapshot.getSite(s.getId()));
-    assertSame(s1a, snapshot.getSite(s1a.getId()));
-    assertSame(s1b, snapshot.getSite(s1b.getId()));
-    assertSame(s2, snapshot.getSite(s2.getId()));
+    AhatInstance oUnObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtUnObfSuperSite");
+    Site sUnObfSuperSite = oUnObfSuperSite.getSite();
+    assertEquals("SuperDumpedStuff.java", sUnObfSuperSite.getFilename());
+    assertEquals("allocateObjectAtUnObfSuperSite", sUnObfSuperSite.getMethodName());
+    assertEquals(26, sUnObfSuperSite.getLineNumber());
+    assertSame(sUnObfSuperSite, snapshot.getSite(sUnObfSuperSite.getId()));
+
+    AhatInstance oOverriddenSite = dump.getDumpedAhatInstance("objectAllocatedAtOverriddenSite");
+    Site sOverriddenSite = oOverriddenSite.getSite();
+    assertEquals("DumpedStuff.java", sOverriddenSite.getFilename());
+    assertEquals("allocateObjectAtOverriddenSite", sOverriddenSite.getMethodName());
+    assertEquals(41, sOverriddenSite.getLineNumber());
+    assertSame(sOverriddenSite, snapshot.getSite(sOverriddenSite.getId()));
   }
 }
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.