Merge "Revert "Ensure that methods requiring interpreter entrypoint always have it.""
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 3d1f434..7fae7f6 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -23,10 +23,10 @@
 ifneq ($(TMPDIR),)
 ART_HOST_TEST_DIR := $(TMPDIR)/test-art-$(shell echo $$PPID)
 else
-# Use a BSD checksum calculated from PPID and USER as one of the path
+# Use a BSD checksum calculated from CWD and USER as one of the path
 # components for the test output. This should allow us to run tests from
 # multiple repositories at the same time.
-ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID-${USER} | sum | cut -d ' ' -f1)
+ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$CWD-${USER} | sum | cut -d ' ' -f1)
 endif
 
 # List of known broken tests that we won't attempt to execute. The test name must be the full
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 1f36cb4..45f4e2d 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -155,6 +155,11 @@
   $(TARGET_CORE_IMAGE_interpreter_32) \
   patchoatd-target
 
+ART_GTEST_oat_file_test_HOST_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_oat_file_test_TARGET_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+
 ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
 ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
diff --git a/build/art.go b/build/art.go
index bf6eee6..59480a0 100644
--- a/build/art.go
+++ b/build/art.go
@@ -66,7 +66,7 @@
 			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
 	}
 
-  cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "none")
+  cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "fast")
   cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
 
 	// We need larger stack overflow guards for ASAN, as the compiled code will have
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 164f9c1..d4d72f3 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -249,6 +249,13 @@
     shared_libs: [
         "libart",
     ],
+
+    pgo: {
+        instrumentation: true,
+        profile_file: "dex2oat.profdata",
+        benchmarks: ["dex2oat"],
+        enable_profile_use: false,
+    }
 }
 
 art_cc_library {
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index 713f8eb..893cad2 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -49,7 +49,7 @@
 
 static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
   std::vector<const char*> names;
-  CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item);
+  CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item, mi->dex_method_index);
   if (accessor.HasCodeItem()) {
     DCHECK(mi->dex_file != nullptr);
     const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
@@ -163,7 +163,7 @@
     for (auto mi : compilation_unit.methods) {
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item);
+      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
       const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
       const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
       const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 4e37f4e..44504c1 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -159,7 +159,7 @@
       PositionInfos dex2line_map;
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item);
+      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
       const uint32_t debug_info_offset = accessor.DebugInfoOffset();
       if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
         continue;
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 52cb217..308e75d 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -373,15 +373,15 @@
       CHECK_EQ(quicken_count, dex_compiler.GetQuickenedInfo().size());
     }
     std::vector<uint8_t> quicken_data;
+    QuickenInfoTable::Builder builder(&quicken_data, dex_compiler.GetQuickenedInfo().size());
+    // Length is encoded by the constructor.
     for (QuickenedInfo info : dex_compiler.GetQuickenedInfo()) {
       // Dex pc is not serialized, only used for checking the instructions. Since we access the
       // array based on the index of the quickened instruction, the indexes must line up perfectly.
       // The reader side uses the NeedsIndexForInstruction function too.
       const Instruction& inst = unit.GetCodeItemAccessor().InstructionAt(info.dex_pc);
       CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
-      // Add the index.
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
+      builder.AddIndex(info.dex_member_index);
     }
     InstructionSet instruction_set = driver->GetInstructionSet();
     if (instruction_set == InstructionSet::kThumb2) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c0886d0..8698659 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -424,10 +424,6 @@
     // optimizations that could break that.
     max_level = optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
   }
-  if (!VdexFile::CanEncodeQuickenedData(dex_file)) {
-    // Don't do any dex level optimizations if we cannot encode the quickening.
-    return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
-  }
   if (klass->IsVerified()) {
     // Class is verified so we can enable DEX-to-DEX compilation for performance.
     return max_level;
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index aa3cd98..5262ab6 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -38,9 +38,10 @@
 //   Elf_Ehdr                    - The ELF header.
 //   Elf_Phdr[]                  - Program headers for the linker.
 //   .note.gnu.build-id          - Optional build ID section (SHA-1 digest).
-//   .rodata                     - DEX files and oat metadata.
+//   .rodata                     - Oat metadata.
 //   .text                       - Compiled code.
 //   .bss                        - Zero-initialized writeable section.
+//   .dex                        - Reserved NOBITS space for dex-related data.
 //   .MIPS.abiflags              - MIPS specific section.
 //   .dynstr                     - Names for .dynsym.
 //   .dynsym                     - A few oat-specific dynamic symbols.
@@ -503,6 +504,7 @@
         rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
         text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0),
         bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
+        dex_(this, ".dex", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
         dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize),
         dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_),
         hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)),
@@ -525,6 +527,7 @@
         virtual_address_(0) {
     text_.phdr_flags_ = PF_R | PF_X;
     bss_.phdr_flags_ = PF_R | PF_W;
+    dex_.phdr_flags_ = PF_R;
     dynamic_.phdr_flags_ = PF_R | PF_W;
     dynamic_.phdr_type_ = PT_DYNAMIC;
     eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME;
@@ -538,6 +541,7 @@
   Section* GetRoData() { return &rodata_; }
   Section* GetText() { return &text_; }
   Section* GetBss() { return &bss_; }
+  Section* GetDex() { return &dex_; }
   StringSection* GetStrTab() { return &strtab_; }
   SymbolSection* GetSymTab() { return &symtab_; }
   Section* GetEhFrame() { return &eh_frame_; }
@@ -666,7 +670,8 @@
                              Elf_Word text_size,
                              Elf_Word bss_size,
                              Elf_Word bss_methods_offset,
-                             Elf_Word bss_roots_offset) {
+                             Elf_Word bss_roots_offset,
+                             Elf_Word dex_size) {
     std::string soname(elf_file_path);
     size_t directory_separator_pos = soname.rfind('/');
     if (directory_separator_pos != std::string::npos) {
@@ -679,6 +684,9 @@
     if (bss_size != 0) {
       bss_.AllocateVirtualMemory(bss_size);
     }
+    if (dex_size != 0) {
+      dex_.AllocateVirtualMemory(dex_size);
+    }
     if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
       abiflags_.AllocateVirtualMemory(abiflags_.GetSize());
     }
@@ -725,6 +733,14 @@
       Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4;
       dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
     }
+    if (dex_size != 0u) {
+      Elf_Word oatdex = dynstr_.Add("oatdex");
+      dynsym_.Add(oatdex, &dex_, dex_.GetAddress(), dex_size, STB_GLOBAL, STT_OBJECT);
+      Elf_Word oatdexlastword = dynstr_.Add("oatdexlastword");
+      Elf_Word oatdexlastword_address = dex_.GetAddress() + dex_size - 4;
+      dynsym_.Add(oatdexlastword, &dex_, oatdexlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+    }
+
     Elf_Word soname_offset = dynstr_.Add(soname);
 
     // We do not really need a hash-table since there is so few entries.
@@ -967,6 +983,7 @@
   Section rodata_;
   Section text_;
   Section bss_;
+  Section dex_;
   CachedStringSection dynstr_;
   SymbolSection dynsym_;
   CachedSection hash_;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index af537dd..a1a5692 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -43,7 +43,7 @@
                              CompilerDriver* driver,
                              CodeGenerator* code_generator,
                              OptimizingCompilerStats* compiler_stats,
-                             const uint8_t* interpreter_metadata,
+                             ArrayRef<const uint8_t> interpreter_metadata,
                              VariableSizedHandleScope* handles)
     : graph_(graph),
       dex_file_(&graph->GetDexFile()),
@@ -70,7 +70,6 @@
       compiler_driver_(nullptr),
       code_generator_(nullptr),
       compilation_stats_(nullptr),
-      interpreter_metadata_(nullptr),
       handles_(handles),
       return_type_(return_type) {}
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index c16a3a9..5a1914c 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_OPTIMIZING_BUILDER_H_
 
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "dex/code_item_accessors.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file.h"
@@ -40,7 +41,7 @@
                 CompilerDriver* driver,
                 CodeGenerator* code_generator,
                 OptimizingCompilerStats* compiler_stats,
-                const uint8_t* interpreter_metadata,
+                ArrayRef<const uint8_t> interpreter_metadata,
                 VariableSizedHandleScope* handles);
 
   // Only for unit testing.
@@ -73,7 +74,7 @@
   CodeGenerator* const code_generator_;
 
   OptimizingCompilerStats* const compilation_stats_;
-  const uint8_t* const interpreter_metadata_;
+  const ArrayRef<const uint8_t> interpreter_metadata_;
   VariableSizedHandleScope* const handles_;
   const DataType::Type return_type_;
 
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 13886b3..28f4816 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2097,13 +2097,17 @@
                                                                      Register class_reg) {
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register temp = temps.AcquireW();
-  size_t status_offset = mirror::Class::StatusOffset().SizeValue();
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
 
   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
   // TODO(vixl): Let the MacroAssembler handle MemOperand.
-  __ Add(temp, class_reg, status_offset);
+  __ Add(temp, class_reg, status_byte_offset);
   __ Ldarb(temp, HeapOperand(temp));
-  __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+  __ Cmp(temp, shifted_initialized_value);
   __ B(lo, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 7c6a5fd..f1ad4e1 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7172,11 +7172,14 @@
     LoadClassSlowPathARMVIXL* slow_path, vixl32::Register class_reg) {
   UseScratchRegisterScope temps(GetVIXLAssembler());
   vixl32::Register temp = temps.Acquire();
-  GetAssembler()->LoadFromOffset(kLoadUnsignedByte,
-                                 temp,
-                                 class_reg,
-                                 mirror::Class::StatusOffset().Int32Value());
-  __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
+
+  GetAssembler()->LoadFromOffset(kLoadUnsignedByte, temp, class_reg, status_byte_offset);
+  __ Cmp(temp, shifted_initialized_value);
   __ B(lo, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we may be in a situation where caches are not synced
   // properly. Therefore, we do a memory fence.
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index ebe252a..c8bd5d4 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1915,8 +1915,14 @@
 
 void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
                                                                     Register class_reg) {
-  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
-  __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
+
+  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset);
+  __ LoadConst32(AT, shifted_initialized_value);
   __ Bltu(TMP, AT, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
   __ Sync(0);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 3ea7b82..bbdc3be 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1761,8 +1761,14 @@
 
 void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path,
                                                                       GpuRegister class_reg) {
-  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
-  __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
+
+  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset);
+  __ LoadConst32(AT, shifted_initialized_value);
   __ Bltuc(TMP, AT, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
   __ Sync(0);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6853238..537e97a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6219,8 +6219,13 @@
 
 void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
     SlowPathCode* slow_path, Register class_reg) {
-  __ cmpb(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
-          Immediate(enum_cast<>(ClassStatus::kInitialized)));
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
+
+  __ cmpb(Address(class_reg,  status_byte_offset), Immediate(shifted_initialized_value));
   __ j(kBelow, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
   // No need for memory fence, thanks to the X86 memory model.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 1f8d822..4a64285 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5425,8 +5425,13 @@
 
 void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
     SlowPathCode* slow_path, CpuRegister class_reg) {
-  __ cmpb(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
-          Immediate(enum_cast<>(ClassStatus::kInitialized)));
+  constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
+  const size_t status_byte_offset =
+      mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
+  constexpr uint32_t shifted_initialized_value =
+      enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
+
+  __ cmpb(Address(class_reg,  status_byte_offset), Immediate(shifted_initialized_value));
   __ j(kBelow, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
   // No need for memory fence, thanks to the x86-64 memory model.
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 6eda289..ba4040a 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -74,8 +74,8 @@
 
 class CodegenTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0);
-  void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected);
+  void TestCode(const std::vector<uint16_t>& data, bool has_result = false, int32_t expected = 0);
+  void TestCodeLong(const std::vector<uint16_t>& data, bool has_result, int64_t expected);
   void TestComparison(IfCondition condition,
                       int64_t i,
                       int64_t j,
@@ -83,7 +83,7 @@
                       const CodegenTargetConfig target_config);
 };
 
-void CodegenTest::TestCode(const uint16_t* data, bool has_result, int32_t expected) {
+void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, int32_t expected) {
   for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
     ResetPoolAndAllocator();
     HGraph* graph = CreateCFG(data);
@@ -93,7 +93,8 @@
   }
 }
 
-void CodegenTest::TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
+void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
+                               bool has_result, int64_t expected) {
   for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
     ResetPoolAndAllocator();
     HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
@@ -104,12 +105,12 @@
 }
 
 TEST_F(CodegenTest, ReturnVoid) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
   TestCode(data);
 }
 
 TEST_F(CodegenTest, CFG1) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,
     Instruction::RETURN_VOID);
 
@@ -117,7 +118,7 @@
 }
 
 TEST_F(CodegenTest, CFG2) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,
     Instruction::GOTO | 0x100,
     Instruction::RETURN_VOID);
@@ -126,21 +127,21 @@
 }
 
 TEST_F(CodegenTest, CFG3) {
-  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,
     Instruction::RETURN_VOID,
     Instruction::GOTO | 0xFF00);
 
   TestCode(data1);
 
-  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_16, 3,
     Instruction::RETURN_VOID,
     Instruction::GOTO_16, 0xFFFF);
 
   TestCode(data2);
 
-  const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 4, 0,
     Instruction::RETURN_VOID,
     Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -149,7 +150,7 @@
 }
 
 TEST_F(CodegenTest, CFG4) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,
     Instruction::GOTO | 0x100,
     Instruction::GOTO | 0xFE00);
@@ -158,7 +159,7 @@
 }
 
 TEST_F(CodegenTest, CFG5) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -168,7 +169,7 @@
 }
 
 TEST_F(CodegenTest, IntConstant) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN_VOID);
 
@@ -176,7 +177,7 @@
 }
 
 TEST_F(CodegenTest, Return1) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN | 0);
 
@@ -184,7 +185,7 @@
 }
 
 TEST_F(CodegenTest, Return2) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 0 | 1 << 8,
     Instruction::RETURN | 1 << 8);
@@ -193,7 +194,7 @@
 }
 
 TEST_F(CodegenTest, Return3) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::RETURN | 1 << 8);
@@ -202,7 +203,7 @@
 }
 
 TEST_F(CodegenTest, ReturnIf1) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::IF_EQ, 3,
@@ -213,7 +214,7 @@
 }
 
 TEST_F(CodegenTest, ReturnIf2) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
@@ -224,17 +225,17 @@
 }
 
 // Exercise bit-wise (one's complement) not-int instruction.
-#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
-TEST_F(CodegenTest, TEST_NAME) {                        \
-  const int32_t input = INPUT;                          \
-  const uint16_t input_lo = Low16Bits(input);           \
-  const uint16_t input_hi = High16Bits(input);          \
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(      \
-      Instruction::CONST | 0 << 8, input_lo, input_hi,  \
-      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,         \
-      Instruction::RETURN | 1 << 8);                    \
-                                                        \
-  TestCode(data, true, EXPECTED_OUTPUT);                \
+#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)           \
+TEST_F(CodegenTest, TEST_NAME) {                                  \
+  const int32_t input = INPUT;                                    \
+  const uint16_t input_lo = Low16Bits(input);                     \
+  const uint16_t input_hi = High16Bits(input);                    \
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(     \
+      Instruction::CONST | 0 << 8, input_lo, input_hi,            \
+      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,                   \
+      Instruction::RETURN | 1 << 8);                              \
+                                                                  \
+  TestCode(data, true, EXPECTED_OUTPUT);                          \
 }
 
 NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
@@ -256,7 +257,7 @@
   const uint16_t word1 = High16Bits(Low32Bits(input));                   \
   const uint16_t word2 = Low16Bits(High32Bits(input));                   \
   const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */       \
-  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(                      \
+  const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(           \
       Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,      \
       Instruction::NOT_LONG | 2 << 8 | 0 << 12,                          \
       Instruction::RETURN_WIDE | 2 << 8);                                \
@@ -306,7 +307,7 @@
   const uint16_t word1 = High16Bits(Low32Bits(input));
   const uint16_t word2 = Low16Bits(High32Bits(input));
   const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
-  const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
       Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
       Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
       Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
@@ -318,7 +319,7 @@
 }
 
 TEST_F(CodegenTest, ReturnAdd1) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::ADD_INT, 1 << 8 | 0,
@@ -328,7 +329,7 @@
 }
 
 TEST_F(CodegenTest, ReturnAdd2) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -338,7 +339,7 @@
 }
 
 TEST_F(CodegenTest, ReturnAdd3) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0 << 8,
     Instruction::ADD_INT_LIT8, 3 << 8 | 0,
     Instruction::RETURN);
@@ -347,7 +348,7 @@
 }
 
 TEST_F(CodegenTest, ReturnAdd4) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0 << 8,
     Instruction::ADD_INT_LIT16, 3,
     Instruction::RETURN);
@@ -356,7 +357,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulInt) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::MUL_INT, 1 << 8 | 0,
@@ -366,7 +367,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulInt2addr) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::MUL_INT_2ADDR | 1 << 12,
@@ -376,7 +377,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulLong) {
-  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
     Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
     Instruction::MUL_LONG, 2 << 8 | 0,
@@ -386,7 +387,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulLong2addr) {
-  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
     Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
     Instruction::MUL_LONG_2ADDR | 2 << 12,
@@ -396,7 +397,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulIntLit8) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0 << 8,
     Instruction::MUL_INT_LIT8, 3 << 8 | 0,
     Instruction::RETURN);
@@ -405,7 +406,7 @@
 }
 
 TEST_F(CodegenTest, ReturnMulIntLit16) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0 << 8,
     Instruction::MUL_INT_LIT16, 3,
     Instruction::RETURN);
@@ -578,7 +579,7 @@
 }
 
 TEST_F(CodegenTest, ReturnDivIntLit8) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0 << 8,
     Instruction::DIV_INT_LIT8, 3 << 8 | 0,
     Instruction::RETURN);
@@ -587,7 +588,7 @@
 }
 
 TEST_F(CodegenTest, ReturnDivInt2Addr) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 4 << 12 | 0,
     Instruction::CONST_4 | 2 << 12 | 1 << 8,
     Instruction::DIV_INT_2ADDR | 1 << 12,
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index e1980e0..d271047 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -36,7 +36,7 @@
  public:
   ConstantFoldingTest() : graph_(nullptr) { }
 
-  void TestCode(const uint16_t* data,
+  void TestCode(const std::vector<uint16_t>& data,
                 const std::string& expected_before,
                 const std::string& expected_after_cf,
                 const std::string& expected_after_dce,
@@ -100,7 +100,7 @@
  *     return v1                2.      return v1
  */
 TEST_F(ConstantFoldingTest, IntConstantFoldingNegation) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::NEG_INT | 1 << 8 | 0 << 12,
     Instruction::RETURN | 1 << 8);
@@ -161,7 +161,7 @@
   const uint16_t word1 = High16Bits(Low32Bits(input));
   const uint16_t word2 = Low16Bits(High32Bits(input));
   const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
-  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
     Instruction::NEG_LONG | 2 << 8 | 0 << 12,
     Instruction::RETURN_WIDE | 2 << 8);
@@ -219,7 +219,7 @@
  *     return v2                4.      return v2
  */
 TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
@@ -284,7 +284,7 @@
  *     return v2                8.      return v2
  */
 TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
@@ -369,7 +369,7 @@
  *     return v2                4.      return v2
  */
 TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 3 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
@@ -432,7 +432,7 @@
  *     return (v4, v5)          6.      return-wide v4
  */
 TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) {
-  const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE_16 | 0 << 8, 1,
     Instruction::CONST_WIDE_16 | 2 << 8, 2,
     Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
@@ -496,7 +496,7 @@
  *     return (v4, v5)          6.      return-wide v4
  */
 TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) {
-  const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE_16 | 0 << 8, 3,
     Instruction::CONST_WIDE_16 | 2 << 8, 2,
     Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
@@ -569,7 +569,7 @@
  *     return v2                13.     return v2
  */
 TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
@@ -672,7 +672,7 @@
  *     return-void              7.      return
  */
 TEST_F(ConstantFoldingTest, ConstantCondition) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::CONST_4 | 0 << 8 | 0 << 12,
     Instruction::IF_GEZ | 1 << 8, 3,
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 929572e..adb6ce1 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -29,12 +29,12 @@
 
 class DeadCodeEliminationTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data,
+  void TestCode(const std::vector<uint16_t>& data,
                 const std::string& expected_before,
                 const std::string& expected_after);
 };
 
-void DeadCodeEliminationTest::TestCode(const uint16_t* data,
+void DeadCodeEliminationTest::TestCode(const std::vector<uint16_t>& data,
                                        const std::string& expected_before,
                                        const std::string& expected_after) {
   HGraph* graph = CreateCFG(data);
@@ -73,7 +73,7 @@
  *     return-void              7.      return
  */
 TEST_F(DeadCodeEliminationTest, AdditionAndConditionalJump) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::CONST_4 | 0 << 8 | 0 << 12,
     Instruction::IF_GEZ | 1 << 8, 3,
@@ -135,7 +135,7 @@
  *     return                   13.     return-void
  */
 TEST_F(DeadCodeEliminationTest, AdditionsAndInconditionalJumps) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 0 << 12,
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index 572466e..1d72ba1 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -26,10 +26,12 @@
 
 class OptimizerTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data, const uint32_t* blocks, size_t blocks_length);
+  void TestCode(const std::vector<uint16_t>& data, const uint32_t* blocks, size_t blocks_length);
 };
 
-void OptimizerTest::TestCode(const uint16_t* data, const uint32_t* blocks, size_t blocks_length) {
+void OptimizerTest::TestCode(const std::vector<uint16_t>& data,
+                             const uint32_t* blocks,
+                             size_t blocks_length) {
   HGraph* graph = CreateCFG(data);
   ASSERT_EQ(graph->GetBlocks().size(), blocks_length);
   for (size_t i = 0, e = blocks_length; i < e; ++i) {
@@ -49,7 +51,7 @@
 }
 
 TEST_F(OptimizerTest, ReturnVoid) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);  // Block number 1
 
   const uint32_t dominators[] = {
@@ -62,7 +64,7 @@
 }
 
 TEST_F(OptimizerTest, CFG1) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,  // Block number 1
     Instruction::RETURN_VOID);  // Block number 2
 
@@ -77,7 +79,7 @@
 }
 
 TEST_F(OptimizerTest, CFG2) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,  // Block number 1
     Instruction::GOTO | 0x100,  // Block number 2
     Instruction::RETURN_VOID);  // Block number 3
@@ -94,7 +96,7 @@
 }
 
 TEST_F(OptimizerTest, CFG3) {
-  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,    // Block number 1
     Instruction::RETURN_VOID,     // Block number 2
     Instruction::GOTO | 0xFF00);  // Block number 3
@@ -109,14 +111,14 @@
 
   TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
 
-  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_16, 3,
     Instruction::RETURN_VOID,
     Instruction::GOTO_16, 0xFFFF);
 
   TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
 
-  const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 4, 0,
     Instruction::RETURN_VOID,
     Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -125,7 +127,7 @@
 }
 
 TEST_F(OptimizerTest, CFG4) {
-  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
     Instruction::GOTO | 0xFF00);
 
@@ -138,14 +140,14 @@
 
   TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
 
-  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 0, 0);
 
   TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
 }
 
 TEST_F(OptimizerTest, CFG5) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,     // Block number 1
     Instruction::GOTO | 0x100,    // Dead block
     Instruction::GOTO | 0xFE00);  // Block number 2
@@ -162,7 +164,7 @@
 }
 
 TEST_F(OptimizerTest, CFG6) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -181,7 +183,7 @@
 }
 
 TEST_F(OptimizerTest, CFG7) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
     Instruction::GOTO | 0x100,    // Block number 2
@@ -201,7 +203,7 @@
 }
 
 TEST_F(OptimizerTest, CFG8) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
     Instruction::GOTO | 0x200,    // Block number 2
@@ -222,7 +224,7 @@
 }
 
 TEST_F(OptimizerTest, CFG9) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
     Instruction::GOTO | 0x200,    // Block number 2
@@ -243,7 +245,7 @@
 }
 
 TEST_F(OptimizerTest, CFG10) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,  // Block number 1
     Instruction::IF_EQ, 3,  // Block number 2
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index b799fb4..75b8e96 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -31,7 +31,7 @@
 
 TEST_F(FindLoopsTest, CFG1) {
   // Constant is not used.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN_VOID);
 
@@ -42,7 +42,7 @@
 }
 
 TEST_F(FindLoopsTest, CFG2) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
@@ -53,7 +53,7 @@
 }
 
 TEST_F(FindLoopsTest, CFG3) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -67,7 +67,7 @@
 }
 
 TEST_F(FindLoopsTest, CFG4) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -82,7 +82,7 @@
 }
 
 TEST_F(FindLoopsTest, CFG5) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -126,7 +126,7 @@
   // while (a == a) {
   // }
   // return;
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0xFE00,
@@ -150,7 +150,7 @@
   // while (a == a) {
   // }
   // return a;
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x400,
     Instruction::IF_EQ, 4,
@@ -173,7 +173,7 @@
 TEST_F(FindLoopsTest, Loop3) {
   // Make sure we create a preheader of a loop when a header originally has two
   // incoming blocks and one back edge.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -197,7 +197,7 @@
 
 TEST_F(FindLoopsTest, Loop4) {
   // Test loop with originally two back edges.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
     Instruction::IF_EQ, 3,
@@ -221,7 +221,7 @@
 
 TEST_F(FindLoopsTest, Loop5) {
   // Test loop with two exit edges.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
     Instruction::IF_EQ, 3,
@@ -244,7 +244,7 @@
 }
 
 TEST_F(FindLoopsTest, InnerLoop) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
     Instruction::IF_EQ, 3,
@@ -273,7 +273,7 @@
 }
 
 TEST_F(FindLoopsTest, TwoLoops) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0xFE00,  // first loop
@@ -301,7 +301,7 @@
 }
 
 TEST_F(FindLoopsTest, NonNaturalLoop) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x0100,
@@ -317,7 +317,7 @@
 }
 
 TEST_F(FindLoopsTest, DoWhileLoop) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x0100,
     Instruction::IF_EQ, 0xFFFF,
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc
index 9ca3e49..08bfa5d 100644
--- a/compiler/optimizing/graph_checker_test.cc
+++ b/compiler/optimizing/graph_checker_test.cc
@@ -22,7 +22,7 @@
 class GraphCheckerTest : public OptimizingUnitTest {
  protected:
   HGraph* CreateSimpleCFG();
-  void TestCode(const uint16_t* data);
+  void TestCode(const std::vector<uint16_t>& data);
 };
 
 /**
@@ -48,7 +48,7 @@
   return graph;
 }
 
-void GraphCheckerTest::TestCode(const uint16_t* data) {
+void GraphCheckerTest::TestCode(const std::vector<uint16_t>& data) {
   HGraph* graph = CreateCFG(data);
   ASSERT_NE(graph, nullptr);
 
@@ -58,14 +58,14 @@
 }
 
 TEST_F(GraphCheckerTest, ReturnVoid) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);
 
   TestCode(data);
 }
 
 TEST_F(GraphCheckerTest, CFG1) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
       Instruction::GOTO | 0x100,
       Instruction::RETURN_VOID);
 
@@ -73,7 +73,7 @@
 }
 
 TEST_F(GraphCheckerTest, CFG2) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -83,7 +83,7 @@
 }
 
 TEST_F(GraphCheckerTest, CFG3) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -128,7 +128,7 @@
 
 TEST_F(GraphCheckerTest, SSAPhi) {
   // This code creates one Phi function during the conversion to SSA form.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 0,
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index b2ad8ec..81a7558 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1660,7 +1660,7 @@
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
   const DexFile& callee_dex_file = *resolved_method->GetDexFile();
   uint32_t method_index = resolved_method->GetDexMethodIndex();
-  CodeItemDebugInfoAccessor code_item_accessor(callee_dex_file, code_item);
+  CodeItemDebugInfoAccessor code_item_accessor(resolved_method);
   ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
   Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
                                                             caller_compilation_unit_.GetDexCache(),
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 72a93c1..64a1ecc 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -49,7 +49,7 @@
                                          const DexCompilationUnit* outer_compilation_unit,
                                          CompilerDriver* compiler_driver,
                                          CodeGenerator* code_generator,
-                                         const uint8_t* interpreter_metadata,
+                                         ArrayRef<const uint8_t> interpreter_metadata,
                                          OptimizingCompilerStats* compiler_stats,
                                          VariableSizedHandleScope* handles,
                                          ScopedArenaAllocator* local_allocator)
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 708a097..4428c53 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 
+#include "base/array_ref.h"
 #include "base/scoped_arena_allocator.h"
 #include "base/scoped_arena_containers.h"
 #include "data_type.h"
@@ -57,7 +58,7 @@
                       const DexCompilationUnit* outer_compilation_unit,
                       CompilerDriver* compiler_driver,
                       CodeGenerator* code_generator,
-                      const uint8_t* interpreter_metadata,
+                      ArrayRef<const uint8_t> interpreter_metadata,
                       OptimizingCompilerStats* compiler_stats,
                       VariableSizedHandleScope* handles,
                       ScopedArenaAllocator* local_allocator);
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 43b63a7..9fa5b74 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -35,11 +35,12 @@
 class LinearizeTest : public OptimizingUnitTest {
  protected:
   template <size_t number_of_blocks>
-  void TestCode(const uint16_t* data, const uint32_t (&expected_order)[number_of_blocks]);
+  void TestCode(const std::vector<uint16_t>& data,
+                const uint32_t (&expected_order)[number_of_blocks]);
 };
 
 template <size_t number_of_blocks>
-void LinearizeTest::TestCode(const uint16_t* data,
+void LinearizeTest::TestCode(const std::vector<uint16_t>& data,
                              const uint32_t (&expected_order)[number_of_blocks]) {
   HGraph* graph = CreateCFG(data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
@@ -68,7 +69,7 @@
   //               + /   \  +
   //           Block4   Block8
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 5,
     Instruction::IF_EQ, 0xFFFE,
@@ -93,7 +94,7 @@
   //               + /   \  +
   //           Block5   Block8
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::RETURN_VOID,
@@ -119,7 +120,7 @@
   //           Block6  + Block9
   //             |     +
   //           Block4 ++
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::RETURN_VOID,
@@ -149,7 +150,7 @@
   //                  + /    \   +
   //                Block5  Block11
   */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 7,
     Instruction::IF_EQ, 0xFFFE,
@@ -179,7 +180,7 @@
   //                   +/    \   +
   //                Block6  Block11
   */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::RETURN_VOID,
@@ -205,7 +206,7 @@
   //       Block5 <- Block9 Block6  +
   //         |
   //       Block7
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x0100,
     Instruction::IF_EQ, 0x0004,
@@ -233,7 +234,7 @@
   //     |
   //   Block7
   //
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x0100,
     Instruction::IF_EQ, 0x0005,
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index e45d7c8..6666066 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -31,10 +31,10 @@
 
 class LiveRangesTest : public OptimizingUnitTest {
  public:
-  HGraph* BuildGraph(const uint16_t* data);
+  HGraph* BuildGraph(const std::vector<uint16_t>& data);
 };
 
-HGraph* LiveRangesTest::BuildGraph(const uint16_t* data) {
+HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) {
   HGraph* graph = CreateCFG(data);
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
@@ -57,7 +57,7 @@
    *           |
    *       12: exit
    */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
@@ -102,7 +102,7 @@
    *         |
    *       26: exit
    */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -151,7 +151,7 @@
    *         |
    *       28: exit
    */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -225,7 +225,7 @@
    *       30: exit
    */
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -304,7 +304,7 @@
    * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
    */
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
     Instruction::ADD_INT, 0, 0,
@@ -378,7 +378,7 @@
    *
    * We want to make sure the constant0 has a lifetime hole after the 16: add.
    */
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::IF_EQ, 5,
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 35bc4ff..6621a03 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -31,7 +31,7 @@
 
 class LivenessTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data, const char* expected);
+  void TestCode(const std::vector<uint16_t>& data, const char* expected);
 };
 
 static void DumpBitVector(BitVector* vector,
@@ -46,7 +46,7 @@
   buffer << ")\n";
 }
 
-void LivenessTest::TestCode(const uint16_t* data, const char* expected) {
+void LivenessTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
   HGraph* graph = CreateCFG(data);
   // `Inline` conditions into ifs.
   PrepareForRegisterAllocation(graph).Run();
@@ -86,7 +86,7 @@
     "  kill: (0)\n";
 
   // Constant is not used.
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN_VOID);
 
@@ -108,7 +108,7 @@
     "  live out: (0)\n"
     "  kill: (0)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
@@ -134,7 +134,7 @@
     "  live out: (000)\n"
     "  kill: (000)\n";
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
     Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -181,7 +181,7 @@
     "  live out: (0000)\n"
     "  kill: (0000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -228,7 +228,7 @@
     "  live out: (000)\n"
     "  kill: (000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -273,7 +273,7 @@
     "  kill: (000)\n";
 
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -318,7 +318,7 @@
     "  live out: (0000)\n"
     "  kill: (0000)\n";
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -370,7 +370,7 @@
     "  live out: (000)\n"
     "  kill: (000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x500,
     Instruction::IF_EQ, 5,
@@ -425,7 +425,7 @@
     "  live out: (0001)\n"
     "  kill: (0001)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -475,7 +475,7 @@
     "  live out: (0000)\n"
     "  kill: (0000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 8,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -530,7 +530,7 @@
     "  live out: (00000)\n"
     "  kill: (00000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 8,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -580,7 +580,7 @@
     "  live out: (000)\n"
     "  kill: (000)\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
     Instruction::ADD_INT, 0, 0,
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index e2b2106..d20b681 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -41,7 +41,7 @@
 // Run the tests only on host.
 #ifndef ART_TARGET_ANDROID
 
-class OptimizingCFITest : public CFITest {
+class OptimizingCFITest : public CFITest, public OptimizingUnitTestHelper {
  public:
   // Enable this flag to generate the expected outputs.
   static constexpr bool kGenerateExpected = false;
@@ -63,7 +63,7 @@
     // Setup simple context.
     std::string error;
     isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error);
-    graph_ = CreateGraph(&pool_and_allocator_);
+    graph_ = CreateGraph();
     // Generate simple frame with some spills.
     code_gen_ = CodeGenerator::Create(graph_, isa, *isa_features_, opts_);
     code_gen_->GetAssembler()->cfi().SetEnabled(true);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f4115f7..a3b1f0c 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -772,7 +772,7 @@
     return nullptr;
   }
 
-  CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item);
+  CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx);
   HGraph* graph = new (allocator) HGraph(
       allocator,
       arena_stack,
@@ -783,7 +783,7 @@
       compiler_driver->GetCompilerOptions().GetDebuggable(),
       osr);
 
-  const uint8_t* interpreter_metadata = nullptr;
+  ArrayRef<const uint8_t> interpreter_metadata;
   // For AOT compilation, we may not get a method, for example if its class is erroneous.
   // JIT should always have a method.
   DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
@@ -940,7 +940,7 @@
                           compiler_driver,
                           codegen.get(),
                           compilation_stats_.get(),
-                          /* interpreter_metadata */ nullptr,
+                          /* interpreter_metadata */ ArrayRef<const uint8_t>(),
                           handles);
     builder.BuildIntrinsicGraph(method);
   }
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 8c97d57..6dcbadb 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -17,12 +17,16 @@
 #ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
 #define ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
 
+#include <memory>
+#include <vector>
+
 #include "base/scoped_arena_allocator.h"
 #include "builder.h"
 #include "common_compiler_test.h"
 #include "dex/code_item_accessors-inl.h"
 #include "dex/dex_file.h"
 #include "dex/dex_instruction.h"
+#include "dex/standard_dex_file.h"
 #include "driver/dex_compilation_unit.h"
 #include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
@@ -99,18 +103,11 @@
   ScopedArenaAllocator scoped_allocator_;
 };
 
-inline HGraph* CreateGraph(ArenaPoolAndAllocator* pool_and_allocator) {
-  return new (pool_and_allocator->GetAllocator()) HGraph(
-      pool_and_allocator->GetAllocator(),
-      pool_and_allocator->GetArenaStack(),
-      *reinterpret_cast<DexFile*>(pool_and_allocator->GetAllocator()->Alloc(sizeof(DexFile))),
-      /*method_idx*/-1,
-      kRuntimeISA);
-}
-
-class OptimizingUnitTest : public CommonCompilerTest {
- protected:
-  OptimizingUnitTest() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
+// Have a separate helper so the OptimizingCFITest can inherit it without causing
+// multiple inheritance errors from having two gtest as a parent twice.
+class OptimizingUnitTestHelper {
+ public:
+  OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
 
   ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); }
   ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); }
@@ -122,14 +119,42 @@
   }
 
   HGraph* CreateGraph() {
-    return art::CreateGraph(pool_and_allocator_.get());
+    ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator();
+
+    // Reserve a big array of 0s so the dex file constructor can offsets from the header.
+    static constexpr size_t kDexDataSize = 4 * KB;
+    const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize));
+
+    // Create the dex file based on the fake data. Call the constructor so that we can use virtual
+    // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks.
+    dex_files_.emplace_back(new StandardDexFile(
+        dex_data,
+        sizeof(StandardDexFile::Header),
+        "no_location",
+        /*location_checksum*/ 0,
+        /*oat_dex_file*/ nullptr,
+        /*container*/ nullptr));
+
+    return new (allocator) HGraph(
+        allocator,
+        pool_and_allocator_->GetArenaStack(),
+        *dex_files_.back(),
+        /*method_idx*/-1,
+        kRuntimeISA);
   }
 
   // Create a control-flow graph from Dex instructions.
-  HGraph* CreateCFG(const uint16_t* data, DataType::Type return_type = DataType::Type::kInt32) {
-    const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(data);
+  HGraph* CreateCFG(const std::vector<uint16_t>& data,
+                    DataType::Type return_type = DataType::Type::kInt32) {
     HGraph* graph = CreateGraph();
 
+    // The code item data might not aligned to 4 bytes, copy it to ensure that.
+    const size_t code_item_size = data.size() * sizeof(data.front());
+    void* aligned_data = GetAllocator()->Alloc(code_item_size);
+    memcpy(aligned_data, &data[0], code_item_size);
+    CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment);
+    const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(aligned_data);
+
     {
       ScopedObjectAccess soa(Thread::Current());
       if (handles_ == nullptr) {
@@ -146,7 +171,7 @@
               /* access_flags */ 0u,
               /* verified_method */ nullptr,
               handles_->NewHandle<mirror::DexCache>(nullptr));
-      CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item);
+      CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u);
       HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type);
       bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
       return graph_built ? graph : nullptr;
@@ -154,10 +179,13 @@
   }
 
  private:
+  std::vector<std::unique_ptr<const StandardDexFile>> dex_files_;
   std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_;
   std::unique_ptr<VariableSizedHandleScope> handles_;
 };
 
+class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {};
+
 // Naive string diff data type.
 typedef std::list<std::pair<std::string, std::string>> diff_t;
 
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 4fc7fe9..6ef386b 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -29,10 +29,10 @@
 
 class PrettyPrinterTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data, const char* expected);
+  void TestCode(const std::vector<uint16_t>& data, const char* expected);
 };
 
-void PrettyPrinterTest::TestCode(const uint16_t* data, const char* expected) {
+void PrettyPrinterTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
   HGraph* graph = CreateCFG(data);
   StringPrettyPrinter printer(graph);
   printer.VisitInsertionOrder();
@@ -40,7 +40,7 @@
 }
 
 TEST_F(PrettyPrinterTest, ReturnVoid) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);
 
   const char* expected =
@@ -67,7 +67,7 @@
       "BasicBlock 3, pred: 2\n"
       "  4: Exit\n";
 
-  const uint16_t data[] =
+  const std::vector<uint16_t> data =
     ZERO_REGISTER_CODE_ITEM(
       Instruction::GOTO | 0x100,
       Instruction::RETURN_VOID);
@@ -89,7 +89,7 @@
       "BasicBlock 4, pred: 3\n"
       "  5: Exit\n";
 
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,
     Instruction::GOTO | 0x100,
     Instruction::RETURN_VOID);
@@ -111,21 +111,21 @@
       "BasicBlock 4, pred: 2\n"
       "  5: Exit\n";
 
-  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,
     Instruction::RETURN_VOID,
     Instruction::GOTO | 0xFF00);
 
   TestCode(data1, expected);
 
-  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_16, 3,
     Instruction::RETURN_VOID,
     Instruction::GOTO_16, 0xFFFF);
 
   TestCode(data2, expected);
 
-  const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 4, 0,
     Instruction::RETURN_VOID,
     Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -144,13 +144,13 @@
       "BasicBlock 3, pred: 0, succ: 1\n"
       "  0: Goto 1\n";
 
-  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
     Instruction::GOTO | 0xFF00);
 
   TestCode(data1, expected);
 
-  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 0, 0);
 
   TestCode(data2, expected);
@@ -166,7 +166,7 @@
       "BasicBlock 3, pred: 1\n"
       "  3: Exit\n";
 
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,
     Instruction::GOTO | 0x100,
     Instruction::GOTO | 0xFE00);
@@ -192,7 +192,7 @@
       "BasicBlock 5, pred: 1, succ: 3\n"
       "  0: Goto 3\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -220,7 +220,7 @@
       "BasicBlock 6, pred: 1, succ: 2\n"
       "  1: Goto 2\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -240,7 +240,7 @@
       "BasicBlock 2, pred: 1\n"
       "  4: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN_VOID);
 
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 3748d59..a70b066 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -46,7 +46,7 @@
   void ExpectedInRegisterHint(Strategy strategy);
 
   // Helper functions that make use of the OptimizingUnitTest's members.
-  bool Check(const uint16_t* data, Strategy strategy);
+  bool Check(const std::vector<uint16_t>& data, Strategy strategy);
   void CFG1(Strategy strategy);
   void Loop1(Strategy strategy);
   void Loop2(Strategy strategy);
@@ -79,7 +79,7 @@
   test_name(Strategy::kRegisterAllocatorGraphColor);\
 }
 
-bool RegisterAllocatorTest::Check(const uint16_t* data, Strategy strategy) {
+bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) {
   HGraph* graph = CreateCFG(data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
@@ -185,7 +185,7 @@
    *        |
    *       exit
    */
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
@@ -222,7 +222,7 @@
    *       exit
    */
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -268,7 +268,7 @@
    *       exit
    */
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 8 << 12 | 1 << 8,
     Instruction::IF_EQ | 1 << 8, 7,
@@ -314,7 +314,7 @@
    *       exit
    */
 
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
     Instruction::CONST_4 | 5 << 12 | 2 << 8,
@@ -351,7 +351,7 @@
 TEST_ALL_STRATEGIES(Loop3);
 
 TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
     Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
@@ -402,7 +402,7 @@
    *  } while (true);
    */
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::CONST_4 | 1 << 8 | 0,
     Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
@@ -432,7 +432,7 @@
  * This test only applies to the linear scan allocator.
  */
 TEST_F(RegisterAllocatorTest, FreeUntil) {
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index 104ebc7..fb15fc8 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -182,7 +182,9 @@
     scheduler->Schedule(graph_);
   }
 
-  void CompileWithRandomSchedulerAndRun(const uint16_t* data, bool has_result, int expected) {
+  void CompileWithRandomSchedulerAndRun(const std::vector<uint16_t>& data,
+                                        bool has_result,
+                                        int expected) {
     for (CodegenTargetConfig target_config : GetTargetConfigs()) {
       HGraph* graph = CreateCFG(data);
 
@@ -393,7 +395,7 @@
   //  }
   //  return result;
   //
-  const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 12 | 2 << 8,          // const/4 v2, #int 0
     Instruction::CONST_HIGH16 | 0 << 8, 0x4120,       // const/high16 v0, #float 10.0 // #41200000
     Instruction::CONST_4 | 1 << 12 | 1 << 8,          // const/4 v1, #int 1
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 77e70d7..85ed06e 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -31,7 +31,7 @@
 
 class SsaTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data, const char* expected);
+  void TestCode(const std::vector<uint16_t>& data, const char* expected);
 };
 
 class SsaPrettyPrinter : public HPrettyPrinter {
@@ -80,7 +80,7 @@
   }
 }
 
-void SsaTest::TestCode(const uint16_t* data, const char* expected) {
+void SsaTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
   HGraph* graph = CreateCFG(data);
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
@@ -119,7 +119,7 @@
     "BasicBlock 5, pred: 1, succ: 3\n"
     "  7: Goto\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::GOTO | 0x100,
@@ -150,7 +150,7 @@
     "BasicBlock 5, pred: 1, succ: 3\n"
     "  9: Goto\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -181,7 +181,7 @@
     "BasicBlock 5, pred: 4\n"
     "  10: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -214,7 +214,7 @@
     "BasicBlock 6, pred: 5\n"
     "  10: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -245,7 +245,7 @@
     "BasicBlock 5, pred: 4\n"
     "  9: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -276,7 +276,7 @@
     "BasicBlock 5, pred: 4\n"
     "  10: Exit\n";
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -310,7 +310,7 @@
     "BasicBlock 6, pred: 5\n"
     "  10: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x500,
     Instruction::IF_EQ, 5,
@@ -351,7 +351,7 @@
     "  13: Phi(2, 1) [11, 8, 8]\n"
     "  14: Goto\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -390,7 +390,7 @@
     "BasicBlock 7, pred: 6\n"
     "  13: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 8,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -432,7 +432,7 @@
     "BasicBlock 8, pred: 2, succ: 6\n"
     "  15: Goto\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 8,
     Instruction::CONST_4 | 4 << 12 | 0,
@@ -456,7 +456,7 @@
     "BasicBlock 2, pred: 1\n"
     "  3: Exit\n";
 
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN_VOID);
 
@@ -484,7 +484,7 @@
     "BasicBlock 5, pred: 1, succ: 3\n"
     "  8: Goto\n";
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
@@ -520,7 +520,7 @@
     "BasicBlock 7, pred: 3, succ: 5\n"
     "  12: Goto\n";
 
-  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+  const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 5,
     Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
index 7e83f8c..33823e2 100644
--- a/compiler/optimizing/suspend_check_test.cc
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -30,10 +30,10 @@
 
 class SuspendCheckTest : public OptimizingUnitTest {
  protected:
-  void TestCode(const uint16_t* data);
+  void TestCode(const std::vector<uint16_t>& data);
 };
 
-void SuspendCheckTest::TestCode(const uint16_t* data) {
+void SuspendCheckTest::TestCode(const std::vector<uint16_t>& data) {
   HGraph* graph = CreateCFG(data);
   HBasicBlock* first_block = graph->GetEntryBlock()->GetSingleSuccessor();
   HBasicBlock* loop_header = first_block->GetSingleSuccessor();
@@ -43,7 +43,7 @@
 }
 
 TEST_F(SuspendCheckTest, CFG1) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
     Instruction::GOTO | 0xFF00);
 
@@ -51,14 +51,14 @@
 }
 
 TEST_F(SuspendCheckTest, CFG2) {
-  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 0, 0);
 
   TestCode(data);
 }
 
 TEST_F(SuspendCheckTest, CFG3) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 0xFFFF,
     Instruction::RETURN_VOID);
@@ -67,7 +67,7 @@
 }
 
 TEST_F(SuspendCheckTest, CFG4) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_NE, 0xFFFF,
     Instruction::RETURN_VOID);
@@ -76,7 +76,7 @@
 }
 
 TEST_F(SuspendCheckTest, CFG5) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQZ, 0xFFFF,
     Instruction::RETURN_VOID);
@@ -85,7 +85,7 @@
 }
 
 TEST_F(SuspendCheckTest, CFG6) {
-  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+  const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_NEZ, 0xFFFF,
     Instruction::RETURN_VOID);
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h
index 04fba51..58f1ec7 100644
--- a/compiler/utils/test_dex_file_builder.h
+++ b/compiler/utils/test_dex_file_builder.h
@@ -27,6 +27,7 @@
 #include <android-base/logging.h>
 
 #include "base/bit_utils.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "dex/standard_dex_file.h"
 
@@ -233,7 +234,8 @@
     static constexpr bool kVerify = false;
     static constexpr bool kVerifyChecksum = false;
     std::string error_msg;
-    std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(
+    const ArtDexFileLoader dex_file_loader;
+    std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(
         &dex_file_data_[0],
         dex_file_data_.size(),
         dex_location,
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 6bebf7d..dc71b9b 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -129,6 +129,18 @@
     static_libs: [
         "libart-dex2oat",
     ],
+
+    pgo: {
+        instrumentation: true,
+        profile_file: "dex2oat.profdata",
+        benchmarks: ["dex2oat"],
+        enable_profile_use: false,
+        cflags: [
+            // Ignore frame-size increase resulting from instrumentation.
+            "-Wno-frame-larger-than=",
+            "-DART_PGO_INSTRUMENTATION",
+        ],
+    }
 }
 
 art_cc_binary {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index dabe07f..83a8656 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1807,9 +1807,7 @@
       // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
       // optimization does not depend on the boot image (the optimization relies on not
       // having final fields in a class, which does not change for an app).
-      VdexFile::Unquicken(dex_files_,
-                          input_vdex_file_->GetQuickeningInfo(),
-                          /* decompile_return_instruction */ false);
+      input_vdex_file_->Unquicken(dex_files_, /* decompile_return_instruction */ false);
     } else {
       // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
       // the results for all the dex files, not just the results for the current dex file.
@@ -2015,8 +2013,8 @@
                                           text_size,
                                           oat_writer->GetBssSize(),
                                           oat_writer->GetBssMethodsOffset(),
-                                          oat_writer->GetBssRootsOffset());
-
+                                          oat_writer->GetBssRootsOffset(),
+                                          oat_writer->GetVdexSize());
         if (IsImage()) {
           // Update oat layout.
           DCHECK(image_writer_ != nullptr);
@@ -3063,9 +3061,9 @@
 int main(int argc, char** argv) {
   int result = static_cast<int>(art::Dex2oat(argc, argv));
   // Everything was done, do an explicit exit here to avoid running Runtime destructors that take
-  // time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class
-  // should not destruct the runtime in this case.
-  if (!art::kIsDebugBuild && (RUNNING_ON_MEMORY_TOOL == 0)) {
+  // time (bug 10645725) unless we're a debug or instrumented build or running on valgrind. Note:
+  // The Dex2Oat class should not destruct the runtime in this case.
+  if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && (RUNNING_ON_MEMORY_TOOL == 0)) {
     _exit(result);
   }
   return result;
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index 980363b..05592f1 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -29,6 +29,7 @@
 #include "base/file_utils.h"
 #include "base/macros.h"
 #include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "jit/profile_compilation_info.h"
@@ -65,12 +66,13 @@
     for (const std::string& dex : GetLibCoreDexFileNames()) {
       std::vector<std::unique_ptr<const DexFile>> dex_files;
       std::string error_msg;
-      CHECK(DexFileLoader::Open(dex.c_str(),
-                                dex,
-                                /*verify*/ true,
-                                /*verify_checksum*/ false,
-                                &error_msg,
-                                &dex_files))
+      const ArtDexFileLoader dex_file_loader;
+      CHECK(dex_file_loader.Open(dex.c_str(),
+                                 dex,
+                                 /*verify*/ true,
+                                 /*verify_checksum*/ false,
+                                 &error_msg,
+                                 &dex_files))
           << error_msg;
       for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
         for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index f176cc2..8799540 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -30,6 +30,7 @@
 #include "base/macros.h"
 #include "base/mutex-inl.h"
 #include "bytecode_utils.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
@@ -108,6 +109,8 @@
                         [](const OatFile&) {});
   }
 
+  bool test_accepts_odex_file_on_failure = false;
+
   template <typename T>
   void GenerateOdexForTest(
       const std::string& dex_location,
@@ -124,7 +127,7 @@
                                                &error_msg,
                                                extra_args,
                                                use_fd);
-    bool success = (status == 0);
+    bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
     if (expect_success) {
       ASSERT_TRUE(success) << error_msg << std::endl << output_;
 
@@ -146,16 +149,18 @@
 
       error_msg_ = error_msg;
 
-      // Verify there's no loadable odex file.
-      std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
-                                                       odex_location.c_str(),
-                                                       nullptr,
-                                                       nullptr,
-                                                       false,
-                                                       /*low_4gb*/false,
-                                                       dex_location.c_str(),
-                                                       &error_msg));
-      ASSERT_TRUE(odex_file.get() == nullptr);
+      if (!test_accepts_odex_file_on_failure) {
+        // Verify there's no loadable odex file.
+        std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                         odex_location.c_str(),
+                                                         nullptr,
+                                                         nullptr,
+                                                         false,
+                                                         /*low_4gb*/false,
+                                                         dex_location.c_str(),
+                                                         &error_msg));
+        ASSERT_TRUE(odex_file.get() == nullptr);
+      }
     }
   }
 
@@ -680,7 +685,8 @@
     const char* location = dex_location.c_str();
     std::string error_msg;
     std::vector<std::unique_ptr<const DexFile>> dex_files;
-    ASSERT_TRUE(DexFileLoader::Open(
+    const ArtDexFileLoader dex_file_loader;
+    ASSERT_TRUE(dex_file_loader.Open(
         location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
     EXPECT_EQ(dex_files.size(), 1U);
     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
@@ -815,7 +821,8 @@
 
     const char* location = dex_location.c_str();
     std::vector<std::unique_ptr<const DexFile>> dex_files;
-    ASSERT_TRUE(DexFileLoader::Open(
+    const ArtDexFileLoader dex_file_loader;
+    ASSERT_TRUE(dex_file_loader.Open(
         location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
     EXPECT_EQ(dex_files.size(), 1U);
     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
@@ -993,7 +1000,12 @@
 
 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
   TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND();  // b/63052624
-  TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS();  // b/63052624
+
+  // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
+  // that the compilation succeeds and the file is completely written by the time the watchdog
+  // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
+  test_accepts_odex_file_on_failure = true;
+
   // Check with ten milliseconds.
   RunTest(false, { "--watchdog-timeout=10" });
 }
diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h
index 0eb36ed..a49112b 100644
--- a/dex2oat/linker/elf_writer.h
+++ b/dex2oat/linker/elf_writer.h
@@ -55,11 +55,17 @@
   virtual ~ElfWriter() {}
 
   virtual void Start() = 0;
+  // Prepares memory layout of the whole ELF file, and creates dynamic symbols
+  // which point to specific areas of interest (usually section begin and end).
+  // This is needed as multi-image needs to know the memory layout of all ELF
+  // files, before starting to write them.
+  // This method must be called before calling GetLoadedSize().
   virtual void PrepareDynamicSection(size_t rodata_size,
                                      size_t text_size,
                                      size_t bss_size,
                                      size_t bss_methods_offset,
-                                     size_t bss_roots_offset) = 0;
+                                     size_t bss_roots_offset,
+                                     size_t dex_section_size) = 0;
   virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual OutputStream* StartRoData() = 0;
   virtual void EndRoData(OutputStream* rodata) = 0;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index aa64b7d..af11d58 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -99,7 +99,8 @@
                              size_t text_size,
                              size_t bss_size,
                              size_t bss_methods_offset,
-                             size_t bss_roots_offset) OVERRIDE;
+                             size_t bss_roots_offset,
+                             size_t dex_section_size) OVERRIDE;
   void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   OutputStream* StartRoData() OVERRIDE;
   void EndRoData(OutputStream* rodata) OVERRIDE;
@@ -183,7 +184,8 @@
                                                      size_t text_size,
                                                      size_t bss_size,
                                                      size_t bss_methods_offset,
-                                                     size_t bss_roots_offset) {
+                                                     size_t bss_roots_offset,
+                                                     size_t dex_section_size) {
   DCHECK_EQ(rodata_size_, 0u);
   rodata_size_ = rodata_size;
   DCHECK_EQ(text_size_, 0u);
@@ -195,7 +197,8 @@
                                   text_size_,
                                   bss_size_,
                                   bss_methods_offset,
-                                  bss_roots_offset);
+                                  bss_roots_offset,
+                                  dex_section_size);
 }
 
 template <typename ElfTypes>
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 85145d3..0671118 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -316,7 +316,8 @@
                                           text_size,
                                           oat_writer->GetBssSize(),
                                           oat_writer->GetBssMethodsOffset(),
-                                          oat_writer->GetBssRootsOffset());
+                                          oat_writer->GetBssRootsOffset(),
+                                          oat_writer->GetVdexSize());
 
         writer->UpdateOatFileLayout(i,
                                     elf_writer->GetLoadedSize(),
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 16d70da..a81fa76 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -33,6 +33,7 @@
 #include "class_table-inl.h"
 #include "compiled_method-inl.h"
 #include "debug/method_debug_info.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_file_types.h"
@@ -57,6 +58,7 @@
 #include "mirror/object-inl.h"
 #include "oat_quick_method_header.h"
 #include "os.h"
+#include "quicken_info.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change-inl.h"
 #include "type_lookup_table.h"
@@ -2617,42 +2619,54 @@
   return true;
 }
 
-class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
+class OatWriter::WriteQuickeningInfoMethodVisitor {
  public:
-  WriteQuickeningInfoMethodVisitor(OatWriter* writer,
-                                   OutputStream* out,
-                                   uint32_t offset,
-                                   SafeMap<const uint8_t*, uint32_t>* offset_map)
-      : DexMethodVisitor(writer, offset),
-        out_(out),
-        written_bytes_(0u),
-        offset_map_(offset_map) {}
+  WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out)
+      : writer_(writer),
+        out_(out) {}
 
-  bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
-      OVERRIDE {
-    uint32_t method_idx = it.GetMemberIndex();
-    CompiledMethod* compiled_method =
-        writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
+  bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
+    std::vector<uint8_t> empty_quicken_info;
+    {
+      // Since we need to be able to access by dex method index, put a one byte empty quicken info
+      // for any method that isn't quickened.
+      QuickenInfoTable::Builder empty_info(&empty_quicken_info, /*num_elements*/ 0u);
+      CHECK(!empty_quicken_info.empty());
+    }
+    for (const DexFile* dex_file : dex_files) {
+      std::vector<uint32_t>* const offsets =
+          &quicken_info_offset_indices_.Put(dex_file, std::vector<uint32_t>())->second;
 
-    if (HasQuickeningInfo(compiled_method)) {
-      ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
-      // Deduplication is already done on a pointer basis by the compiler driver,
-      // so we can simply compare the pointers to find out if things are duplicated.
-      if (offset_map_->find(map.data()) == offset_map_->end()) {
-        uint32_t length = map.size() * sizeof(map.front());
-        offset_map_->Put(map.data(), written_bytes_);
-        if (!out_->WriteFully(&length, sizeof(length)) ||
-            !out_->WriteFully(map.data(), length)) {
-          PLOG(ERROR) << "Failed to write quickening info for "
-                      << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
-                      << out_->GetLocation();
+      // Every method needs an index in the table.
+      for (uint32_t method_idx = 0; method_idx < dex_file->NumMethodIds(); ++method_idx) {
+        ArrayRef<const uint8_t> map(empty_quicken_info);
+
+        // Use the existing quicken info if it exists.
+        MethodReference method_ref(dex_file, method_idx);
+        CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(method_ref);
+        if (compiled_method != nullptr && HasQuickeningInfo(compiled_method)) {
+          map = compiled_method->GetVmapTable();
+        }
+
+        // The current approach prevents deduplication of quicken infos since each method index
+        // has one unique quicken info. Deduplication does not provide much savings for dex indices
+        // since they are rarely duplicated.
+        const uint32_t length = map.size() * sizeof(map.front());
+
+        // Record each index if required. written_bytes_ is the offset from the start of the
+        // quicken info data.
+        if (QuickenInfoOffsetTableAccessor::IsCoveredIndex(method_idx)) {
+          offsets->push_back(written_bytes_);
+        }
+
+        if (!out_->WriteFully(map.data(), length)) {
+          PLOG(ERROR) << "Failed to write quickening info for " << method_ref.PrettyMethod()
+                      << " to " << out_->GetLocation();
           return false;
         }
-        written_bytes_ += sizeof(length) + length;
-        offset_ += sizeof(length) + length;
+        written_bytes_ += length;
       }
     }
-
     return true;
   }
 
@@ -2660,71 +2674,59 @@
     return written_bytes_;
   }
 
+  SafeMap<const DexFile*, std::vector<uint32_t>>& GetQuickenInfoOffsetIndicies() {
+    return quicken_info_offset_indices_;
+  }
+
+
  private:
+  OatWriter* const writer_;
   OutputStream* const out_;
-  size_t written_bytes_;
-  // Maps quickening map to its offset in the file.
-  SafeMap<const uint8_t*, uint32_t>* offset_map_;
+  size_t written_bytes_ = 0u;
+  // Map of offsets for quicken info related to method indices.
+  SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_;
 };
 
-class OatWriter::WriteQuickeningIndicesMethodVisitor {
+class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor {
  public:
-  WriteQuickeningIndicesMethodVisitor(OutputStream* out,
-                                      uint32_t quickening_info_bytes,
-                                      const SafeMap<const uint8_t*, uint32_t>& offset_map)
+  WriteQuickeningInfoOffsetsMethodVisitor(
+      OutputStream* out,
+      uint32_t start_offset,
+      SafeMap<const DexFile*, std::vector<uint32_t>>* quicken_info_offset_indices,
+      std::vector<uint32_t>* out_table_offsets)
       : out_(out),
-        quickening_info_bytes_(quickening_info_bytes),
-        written_bytes_(0u),
-        offset_map_(offset_map) {}
+        start_offset_(start_offset),
+        quicken_info_offset_indices_(quicken_info_offset_indices),
+        out_table_offsets_(out_table_offsets) {}
 
-  bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
+  bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
     for (const DexFile* dex_file : dex_files) {
-      const size_t class_def_count = dex_file->NumClassDefs();
-      for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
-        const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-        const uint8_t* class_data = dex_file->GetClassData(class_def);
-        if (class_data == nullptr) {
-          continue;
-        }
-        for (ClassDataItemIterator class_it(*dex_file, class_data);
-             class_it.HasNext();
-             class_it.Next()) {
-          if (!class_it.IsAtMethod() || class_it.GetMethodCodeItem() == nullptr) {
-            continue;
-          }
-          uint32_t method_idx = class_it.GetMemberIndex();
-          CompiledMethod* compiled_method =
-              driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
-          const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
-          CodeItemDebugInfoAccessor accessor(*dex_file, code_item);
-          const uint32_t existing_debug_info_offset = accessor.DebugInfoOffset();
-          // If the existing offset is already out of bounds (and not magic marker 0xFFFFFFFF)
-          // we will pretend the method has been quickened.
-          bool existing_offset_out_of_bounds =
-              (existing_debug_info_offset >= dex_file->Size() &&
-               existing_debug_info_offset != 0xFFFFFFFF);
-          bool has_quickening_info = HasQuickeningInfo(compiled_method);
-          if (has_quickening_info || existing_offset_out_of_bounds) {
-            uint32_t new_debug_info_offset =
-                dex_file->Size() + quickening_info_bytes_ + written_bytes_;
-            // Abort if overflow.
-            CHECK_GE(new_debug_info_offset, dex_file->Size());
-            const_cast<DexFile::CodeItem*>(code_item)->SetDebugInfoOffset(new_debug_info_offset);
-            uint32_t quickening_offset = has_quickening_info
-                ? offset_map_.Get(compiled_method->GetVmapTable().data())
-                : VdexFile::kNoQuickeningInfoOffset;
-            if (!out_->WriteFully(&existing_debug_info_offset,
-                                  sizeof(existing_debug_info_offset)) ||
-                !out_->WriteFully(&quickening_offset, sizeof(quickening_offset))) {
-              PLOG(ERROR) << "Failed to write quickening info for "
-                          << dex_file->PrettyMethod(method_idx) << " to "
-                          << out_->GetLocation();
-              return false;
-            }
-            written_bytes_ += sizeof(existing_debug_info_offset) + sizeof(quickening_offset);
-          }
-        }
+      auto it = quicken_info_offset_indices_->find(dex_file);
+      DCHECK(it != quicken_info_offset_indices_->end()) << "Failed to find dex file "
+                                                        << dex_file->GetLocation();
+      const std::vector<uint32_t>* const offsets = &it->second;
+
+      const uint32_t current_offset = start_offset_ + written_bytes_;
+      CHECK_ALIGNED_PARAM(current_offset, QuickenInfoOffsetTableAccessor::Alignment());
+
+      // Generate and write the data.
+      std::vector<uint8_t> table_data;
+      QuickenInfoOffsetTableAccessor::Builder builder(&table_data);
+      for (uint32_t offset : *offsets) {
+        builder.AddOffset(offset);
       }
+
+      // Store the offset since we need to put those after the dex file. Table offsets are relative
+      // to the start of the quicken info section.
+      out_table_offsets_->push_back(current_offset);
+
+      const uint32_t length = table_data.size() * sizeof(table_data.front());
+      if (!out_->WriteFully(table_data.data(), length)) {
+        PLOG(ERROR) << "Failed to write quickening offset table for " << dex_file->GetLocation()
+                    << " to " << out_->GetLocation();
+        return false;
+      }
+      written_bytes_ += length;
     }
     return true;
   }
@@ -2735,14 +2737,16 @@
 
  private:
   OutputStream* const out_;
-  const uint32_t quickening_info_bytes_;
-  size_t written_bytes_;
-  // Maps quickening map to its offset in the file.
-  const SafeMap<const uint8_t*, uint32_t>& offset_map_;
+  const uint32_t start_offset_;
+  size_t written_bytes_ = 0u;
+  // Maps containing the offsets for the tables.
+  SafeMap<const DexFile*, std::vector<uint32_t>>* const quicken_info_offset_indices_;
+  std::vector<uint32_t>* const out_table_offsets_;
 };
 
 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
   size_t initial_offset = vdex_size_;
+  // Make sure the table is properly aligned.
   size_t start_offset = RoundUp(initial_offset, 4u);
 
   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
@@ -2753,36 +2757,71 @@
     return false;
   }
 
-  if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+  size_t current_offset = start_offset;
+  if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
     std::vector<uint32_t> dex_files_indices;
-    SafeMap<const uint8_t*, uint32_t> offset_map;
-    WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
-    if (!VisitDexMethods(&visitor1)) {
+    WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out);
+    if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) {
       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
       return false;
     }
 
-    if (visitor1.GetNumberOfWrittenBytes() > 0) {
-      WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
-                                                   visitor1.GetNumberOfWrittenBytes(),
-                                                   offset_map);
-      if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
-        PLOG(ERROR) << "Failed to write the vdex quickening info. File: "
-                    << vdex_out->GetLocation();
+    uint32_t quicken_info_offset = write_quicken_info_visitor.GetNumberOfWrittenBytes();
+    current_offset = current_offset + quicken_info_offset;
+    uint32_t before_offset = current_offset;
+    current_offset = RoundUp(current_offset, QuickenInfoOffsetTableAccessor::Alignment());
+    const size_t extra_bytes = current_offset - before_offset;
+    quicken_info_offset += extra_bytes;
+    actual_offset = vdex_out->Seek(current_offset, kSeekSet);
+    if (actual_offset != static_cast<off_t>(current_offset)) {
+      PLOG(ERROR) << "Failed to seek to quickening offset table section. Actual: " << actual_offset
+                  << " Expected: " << current_offset
+                  << " Output: " << vdex_out->GetLocation();
+      return false;
+    }
+
+    std::vector<uint32_t> table_offsets;
+    WriteQuickeningInfoOffsetsMethodVisitor table_visitor(
+        vdex_out,
+        quicken_info_offset,
+        &write_quicken_info_visitor.GetQuickenInfoOffsetIndicies(),
+        /*out*/ &table_offsets);
+    if (!table_visitor.VisitDexMethods(*dex_files_)) {
+      PLOG(ERROR) << "Failed to write the vdex quickening info. File: "
+                  << vdex_out->GetLocation();
+      return false;
+    }
+
+    CHECK_EQ(table_offsets.size(), dex_files_->size());
+
+    current_offset += table_visitor.GetNumberOfWrittenBytes();
+
+    // Store the offset table offset as a preheader for each dex.
+    size_t index = 0;
+    for (const OatDexFile& oat_dex_file : oat_dex_files_) {
+      const off_t desired_offset = oat_dex_file.dex_file_offset_ -
+          sizeof(VdexFile::QuickeningTableOffsetType);
+      actual_offset = vdex_out->Seek(desired_offset, kSeekSet);
+      if (actual_offset != desired_offset) {
+        PLOG(ERROR) << "Failed to seek to before dex file for writing offset table offset: "
+                    << actual_offset << " Expected: " << desired_offset
+                    << " Output: " << vdex_out->GetLocation();
         return false;
       }
-
-      if (!vdex_out->Flush()) {
-        PLOG(ERROR) << "Failed to flush stream after writing quickening info."
+      uint32_t offset = table_offsets[index];
+      if (!vdex_out->WriteFully(reinterpret_cast<const uint8_t*>(&offset), sizeof(offset))) {
+        PLOG(ERROR) << "Failed to write verifier deps."
                     << " File: " << vdex_out->GetLocation();
         return false;
       }
-      size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
-                              visitor2.GetNumberOfWrittenBytes();
-    } else {
-      // We know we did not quicken.
-      size_quickening_info_ = 0;
+      ++index;
     }
+    if (!vdex_out->Flush()) {
+      PLOG(ERROR) << "Failed to flush stream after writing quickening info."
+                  << " File: " << vdex_out->GetLocation();
+      return false;
+    }
+    size_quickening_info_ = current_offset - start_offset;
   } else {
     // We know we did not quicken.
     size_quickening_info_ = 0;
@@ -3357,9 +3396,15 @@
   // Dex files are required to be 4 byte aligned.
   size_t initial_offset = vdex_size_;
   size_t start_offset = RoundUp(initial_offset, 4);
-  size_t file_offset = start_offset;
   size_dex_file_alignment_ += start_offset - initial_offset;
 
+  // Leave extra room for the quicken offset table offset.
+  start_offset += sizeof(VdexFile::QuickeningTableOffsetType);
+  // TODO: Not count the offset as part of alignment.
+  size_dex_file_alignment_ += sizeof(VdexFile::QuickeningTableOffsetType);
+
+  size_t file_offset = start_offset;
+
   // Seek to the start of the dex file and flush any pending operations in the stream.
   // Verify that, after flushing the stream, the file is at the same offset as the stream.
   off_t actual_offset = out->Seek(file_offset, kSeekSet);
@@ -3392,6 +3437,7 @@
   std::string error_msg;
   std::string location(oat_dex_file->GetLocation());
   std::unique_ptr<const DexFile> dex_file;
+  const ArtDexFileLoader dex_file_loader;
   if (oat_dex_file->source_.IsZipEntry()) {
     ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
     std::unique_ptr<MemMap> mem_map(
@@ -3400,12 +3446,12 @@
       LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
       return false;
     }
-    dex_file = DexFileLoader::Open(location,
-                                   zip_entry->GetCrc32(),
-                                   std::move(mem_map),
-                                   /* verify */ true,
-                                   /* verify_checksum */ true,
-                                   &error_msg);
+    dex_file = dex_file_loader.Open(location,
+                               zip_entry->GetCrc32(),
+                               std::move(mem_map),
+                               /* verify */ true,
+                               /* verify_checksum */ true,
+                               &error_msg);
   } else if (oat_dex_file->source_.IsRawFile()) {
     File* raw_file = oat_dex_file->source_.GetRawFile();
     int dup_fd = dup(raw_file->Fd());
@@ -3413,7 +3459,7 @@
       PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
       return false;
     }
-    dex_file = DexFileLoader::OpenDex(
+    dex_file = dex_file_loader.OpenDex(
         dup_fd, location, /* verify */ true, /* verify_checksum */ true, &error_msg);
   } else {
     // The source data is a vdex file.
@@ -3426,14 +3472,14 @@
     DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
     // Since the source may have had its layout changed, or may be quickened, don't verify it.
-    dex_file = DexFileLoader::Open(raw_dex_file,
-                                   header->file_size_,
-                                   location,
-                                   oat_dex_file->dex_file_location_checksum_,
-                                   nullptr,
-                                   /* verify */ false,
-                                   /* verify_checksum */ false,
-                                   &error_msg);
+    dex_file = dex_file_loader.Open(raw_dex_file,
+                                    header->file_size_,
+                                    location,
+                                    oat_dex_file->dex_file_location_checksum_,
+                                    nullptr,
+                                    /* verify */ false,
+                                    /* verify_checksum */ false,
+                                    &error_msg);
   }
   if (dex_file == nullptr) {
     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
@@ -3653,6 +3699,7 @@
                << " error: " << error_msg;
     return false;
   }
+  const ArtDexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   for (OatDexFile& oat_dex_file : oat_dex_files_) {
     const uint8_t* raw_dex_file =
@@ -3674,14 +3721,14 @@
     }
 
     // Now, open the dex file.
-    dex_files.emplace_back(DexFileLoader::Open(raw_dex_file,
-                                               oat_dex_file.dex_file_size_,
-                                               oat_dex_file.GetLocation(),
-                                               oat_dex_file.dex_file_location_checksum_,
-                                               /* oat_dex_file */ nullptr,
-                                               verify,
-                                               verify,
-                                               &error_msg));
+    dex_files.emplace_back(dex_file_loader.Open(raw_dex_file,
+                                                oat_dex_file.dex_file_size_,
+                                                oat_dex_file.GetLocation(),
+                                                oat_dex_file.dex_file_location_checksum_,
+                                                /* oat_dex_file */ nullptr,
+                                                verify,
+                                                verify,
+                                                &error_msg));
     if (dex_files.back() == nullptr) {
       LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
                  << " Error: " << error_msg;
@@ -3689,7 +3736,7 @@
     }
 
     // Set the class_offsets size now that we have easy access to the DexFile and
-    // it has been verified in DexFileLoader::Open.
+    // it has been verified in dex_file_loader.Open.
     oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
   }
 
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index ba29e3b..824b395 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -230,6 +230,10 @@
     return bss_roots_offset_;
   }
 
+  size_t GetVdexSize() const {
+    return vdex_size_;
+  }
+
   size_t GetOatDataOffset() const {
     return oat_data_offset_;
   }
@@ -271,7 +275,7 @@
   class WriteMapMethodVisitor;
   class WriteMethodInfoVisitor;
   class WriteQuickeningInfoMethodVisitor;
-  class WriteQuickeningIndicesMethodVisitor;
+  class WriteQuickeningInfoOffsetsMethodVisitor;
 
   // Visit all the methods in all the compiled dex files in their definition order
   // with a given DexMethodVisitor.
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 4888060..321a2e4 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -219,7 +219,8 @@
                                       text_size,
                                       oat_writer.GetBssSize(),
                                       oat_writer.GetBssMethodsOffset(),
-                                      oat_writer.GetBssRootsOffset());
+                                      oat_writer.GetBssRootsOffset(),
+                                      oat_writer.GetVdexSize());
 
     std::unique_ptr<BufferedOutputStream> vdex_out =
         std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
@@ -658,7 +659,11 @@
   ASSERT_EQ(dex_file2_data->GetLocation(), opened_dex_file2->GetLocation());
 
   const VdexFile::Header &vdex_header = opened_oat_file->GetVdexFile()->GetHeader();
-  ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
+  if (!compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
+    // If quickening is enabled we will always write the table since there is no special logic that
+    // checks for all methods not being quickened (not worth the complexity).
+    ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
+  }
 
   int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
   ASSERT_GE(actual_vdex_size, 0);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 2c98e12..1518e1d 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -44,6 +44,7 @@
 
 #include "android-base/stringprintf.h"
 
+#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-no_art-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_exception_helpers.h"
@@ -1186,7 +1187,7 @@
  */
 static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
                      const DexFile::CodeItem* pCode, u4 codeOffset) {
-  CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
+  CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
 
   fprintf(gOutFile, "      registers     : %d\n", accessor.RegistersSize());
   fprintf(gOutFile, "      ins           : %d\n", accessor.InsSize());
@@ -1879,8 +1880,10 @@
   // all of which are Zip archives with "classes.dex" inside.
   const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
   std::string error_msg;
+  // TODO: Use DexFileLoader when that is implemented.
+  const ArtDexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFileLoader::Open(
+  if (!dex_file_loader.Open(
         fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index a02f75a..4f5d810 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -34,6 +34,13 @@
     name: "libart-dexlayout",
     defaults: ["libart-dexlayout-defaults"],
     shared_libs: ["libart"],
+
+    pgo: {
+        instrumentation: true,
+        profile_file: "dex2oat.profdata",
+        benchmarks: ["dex2oat"],
+        enable_profile_use: false,
+    }
 }
 
 art_cc_library {
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 1c5b16d..d1dc658 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -16,10 +16,144 @@
 
 #include "compact_dex_writer.h"
 
+#include "base/logging.h"
+#include "base/time_utils.h"
+#include "dex/compact_dex_debug_info.h"
 #include "dex/compact_dex_file.h"
+#include "dexlayout.h"
 
 namespace art {
 
+uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) {
+  const uint32_t start_offset = offset;
+  const dex_ir::Collections& collections = header_->GetCollections();
+  // Debug offsets for method indexes. 0 means no debug info.
+  std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u);
+
+  static constexpr InvokeType invoke_types[] = {
+    kDirect,
+    kVirtual
+  };
+
+  for (InvokeType invoke_type : invoke_types) {
+    for (const std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+      // Skip classes that are not defined in this dex file.
+      dex_ir::ClassData* class_data = class_def->GetClassData();
+      if (class_data == nullptr) {
+        continue;
+      }
+      for (auto& method : *(invoke_type == InvokeType::kDirect
+                                ? class_data->DirectMethods()
+                                : class_data->VirtualMethods())) {
+        const dex_ir::MethodId* method_id = method->GetMethodId();
+        dex_ir::CodeItem* code_item = method->GetCodeItem();
+        if (code_item != nullptr && code_item->DebugInfo() != nullptr) {
+          const uint32_t debug_info_offset = code_item->DebugInfo()->GetOffset();
+          const uint32_t method_idx = method_id->GetIndex();
+          if (debug_info_offsets[method_idx] != 0u) {
+            CHECK_EQ(debug_info_offset, debug_info_offsets[method_idx]);
+          }
+          debug_info_offsets[method_idx] = debug_info_offset;
+        }
+      }
+    }
+  }
+
+  std::vector<uint8_t> data;
+  debug_info_base_ = 0u;
+  debug_info_offsets_table_offset_ = 0u;
+  CompactDexDebugInfoOffsetTable::Build(debug_info_offsets,
+                                        &data,
+                                        &debug_info_base_,
+                                        &debug_info_offsets_table_offset_);
+  // Align the table and write it out.
+  offset = RoundUp(offset, CompactDexDebugInfoOffsetTable::kAlignment);
+  debug_info_offsets_pos_ = offset;
+  offset += Write(data.data(), data.size(), offset);
+
+  // Verify that the whole table decodes as expected and measure average performance.
+  const bool kMeasureAndTestOutput = dex_layout_->GetOptions().verify_output_;
+  if (kMeasureAndTestOutput && !debug_info_offsets.empty()) {
+    uint64_t start_time = NanoTime();
+    CompactDexDebugInfoOffsetTable::Accessor accessor(mem_map_->Begin() + debug_info_offsets_pos_,
+                                                      debug_info_base_,
+                                                      debug_info_offsets_table_offset_);
+
+    for (size_t i = 0; i < debug_info_offsets.size(); ++i) {
+      CHECK_EQ(accessor.GetDebugInfoOffset(i), debug_info_offsets[i]);
+    }
+    uint64_t end_time = NanoTime();
+    VLOG(dex) << "Average lookup time (ns) for debug info offsets: "
+              << (end_time - start_time) / debug_info_offsets.size();
+  }
+
+  return offset - start_offset;
+}
+
+uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
+                                         uint32_t offset,
+                                         bool reserve_only) {
+  DCHECK(code_item != nullptr);
+  const uint32_t start_offset = offset;
+  offset = RoundUp(offset, CompactDexFile::CodeItem::kAlignment);
+  ProcessOffset(&offset, code_item);
+
+  CompactDexFile::CodeItem disk_code_item;
+  disk_code_item.registers_size_ = code_item->RegistersSize();
+  disk_code_item.ins_size_ = code_item->InsSize();
+  disk_code_item.outs_size_ = code_item->OutsSize();
+  disk_code_item.tries_size_ = code_item->TriesSize();
+  disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
+  // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
+  // item.
+  offset += Write(&disk_code_item,
+                  OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_),
+                  offset);
+  // Write the instructions.
+  offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+  // Write the post instruction data.
+  offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
+  return offset - start_offset;
+}
+
+void CompactDexWriter::SortDebugInfosByMethodIndex() {
+  dex_ir::Collections& collections = header_->GetCollections();
+  static constexpr InvokeType invoke_types[] = {
+    kDirect,
+    kVirtual
+  };
+  std::map<const dex_ir::DebugInfoItem*, uint32_t> method_idx_map;
+  for (InvokeType invoke_type : invoke_types) {
+    for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+      // Skip classes that are not defined in this dex file.
+      dex_ir::ClassData* class_data = class_def->GetClassData();
+      if (class_data == nullptr) {
+        continue;
+      }
+      for (auto& method : *(invoke_type == InvokeType::kDirect
+                                ? class_data->DirectMethods()
+                                : class_data->VirtualMethods())) {
+        const dex_ir::MethodId* method_id = method->GetMethodId();
+        dex_ir::CodeItem* code_item = method->GetCodeItem();
+        if (code_item != nullptr && code_item->DebugInfo() != nullptr) {
+          const dex_ir::DebugInfoItem* debug_item = code_item->DebugInfo();
+          method_idx_map.insert(std::make_pair(debug_item, method_id->GetIndex()));
+        }
+      }
+    }
+  }
+  std::sort(collections.DebugInfoItems().begin(),
+            collections.DebugInfoItems().end(),
+            [&](const std::unique_ptr<dex_ir::DebugInfoItem>& a,
+                const std::unique_ptr<dex_ir::DebugInfoItem>& b) {
+    auto it_a = method_idx_map.find(a.get());
+    auto it_b = method_idx_map.find(b.get());
+    uint32_t idx_a = it_a != method_idx_map.end() ? it_a->second : 0u;
+    uint32_t idx_b = it_b != method_idx_map.end() ? it_b->second : 0u;
+    return idx_a < idx_b;
+  });
+}
+
 void CompactDexWriter::WriteHeader() {
   CompactDexFile::Header header;
   CompactDexFile::WriteMagic(&header.magic_[0]);
@@ -49,6 +183,11 @@
   header.class_defs_off_ = collections.ClassDefsOffset();
   header.data_size_ = header_->DataSize();
   header.data_off_ = header_->DataOffset();
+
+  // Compact dex specific flags.
+  header.debug_info_offsets_pos_ = debug_info_offsets_pos_;
+  header.debug_info_offsets_table_offset_ = debug_info_offsets_table_offset_;
+  header.debug_info_base_ = debug_info_base_;
   header.feature_flags_ = 0u;
   // In cases where apps are converted to cdex during install, maintain feature flags so that
   // the verifier correctly verifies apps that aren't targetting default methods.
@@ -62,4 +201,103 @@
   return sizeof(CompactDexFile::Header);
 }
 
+void CompactDexWriter::WriteMemMap() {
+  // Starting offset is right after the header.
+  uint32_t offset = GetHeaderSize();
+
+  dex_ir::Collections& collection = header_->GetCollections();
+
+  // Based on: https://source.android.com/devices/tech/dalvik/dex-format
+  // Since the offsets may not be calculated already, the writing must be done in the correct order.
+  const uint32_t string_ids_offset = offset;
+  offset += WriteStringIds(offset, /*reserve_only*/ true);
+  offset += WriteTypeIds(offset);
+  const uint32_t proto_ids_offset = offset;
+  offset += WriteProtoIds(offset, /*reserve_only*/ true);
+  offset += WriteFieldIds(offset);
+  offset += WriteMethodIds(offset);
+  const uint32_t class_defs_offset = offset;
+  offset += WriteClassDefs(offset, /*reserve_only*/ true);
+  const uint32_t call_site_ids_offset = offset;
+  offset += WriteCallSiteIds(offset, /*reserve_only*/ true);
+  offset += WriteMethodHandles(offset);
+
+  uint32_t data_offset_ = 0u;
+  if (compute_offsets_) {
+    // Data section.
+    offset = RoundUp(offset, kDataSectionAlignment);
+    data_offset_ = offset;
+  }
+
+  // Write code item first to minimize the space required for encoded methods.
+  // For cdex, the code items don't depend on the debug info.
+  offset += WriteCodeItems(offset, /*reserve_only*/ false);
+
+  // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of
+  // the debug info offset table.
+  SortDebugInfosByMethodIndex();
+  offset += WriteDebugInfoItems(offset);
+
+  offset += WriteEncodedArrays(offset);
+  offset += WriteAnnotations(offset);
+  offset += WriteAnnotationSets(offset);
+  offset += WriteAnnotationSetRefs(offset);
+  offset += WriteAnnotationsDirectories(offset);
+  offset += WriteTypeLists(offset);
+  offset += WriteClassDatas(offset);
+  offset += WriteStringDatas(offset);
+
+  // Write delayed id sections that depend on data sections.
+  WriteStringIds(string_ids_offset, /*reserve_only*/ false);
+  WriteProtoIds(proto_ids_offset, /*reserve_only*/ false);
+  WriteClassDefs(class_defs_offset, /*reserve_only*/ false);
+  WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false);
+
+  // Write the map list.
+  if (compute_offsets_) {
+    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList));
+    collection.SetMapListOffset(offset);
+  } else {
+    offset = collection.MapListOffset();
+  }
+  offset += GenerateAndWriteMapItems(offset);
+  offset = RoundUp(offset, kDataSectionAlignment);
+
+  // Map items are included in the data section.
+  if (compute_offsets_) {
+    header_->SetDataSize(offset - data_offset_);
+    if (header_->DataSize() != 0) {
+      // Offset must be zero when the size is zero.
+      header_->SetDataOffset(data_offset_);
+    } else {
+      header_->SetDataOffset(0u);
+    }
+  }
+
+  // Write link data if it exists.
+  const std::vector<uint8_t>& link_data = collection.LinkData();
+  if (link_data.size() > 0) {
+    CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
+    if (compute_offsets_) {
+      header_->SetLinkOffset(offset);
+    }
+    offset += Write(&link_data[0], link_data.size(), header_->LinkOffset());
+  }
+
+  // Write debug info offset table last to make dex file verifier happy.
+  offset += WriteDebugInfoOffsetTable(offset);
+
+  // Write header last.
+  if (compute_offsets_) {
+    header_->SetFileSize(offset);
+  }
+  WriteHeader();
+
+  if (dex_layout_->GetOptions().update_checksum_) {
+    header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset));
+    // Rewrite the header with the calculated checksum.
+    WriteHeader();
+  }
+}
+
 }  // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index d13333b..37f6ff1 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -33,13 +33,30 @@
         compact_dex_level_(compact_dex_level) {}
 
  protected:
+  void WriteMemMap() OVERRIDE;
+
   void WriteHeader() OVERRIDE;
 
   size_t GetHeaderSize() const OVERRIDE;
 
+  uint32_t WriteDebugInfoOffsetTable(uint32_t offset);
+
   const CompactDexLevel compact_dex_level_;
 
+  uint32_t WriteCodeItem(dex_ir::CodeItem* code_item, uint32_t offset, bool reserve_only) OVERRIDE;
+
+  void SortDebugInfosByMethodIndex();
+
  private:
+  // Position in the compact dex file for the debug info table data starts.
+  uint32_t debug_info_offsets_pos_ = 0u;
+
+  // Offset into the debug info table data where the lookup table is.
+  uint32_t debug_info_offsets_table_offset_ = 0u;
+
+  // Base offset of where debug info starts in the dex file.
+  uint32_t debug_info_base_ = 0u;
+
   DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
 };
 
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 2191ea6..0a59cc9 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -566,8 +566,10 @@
 }
 
 CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
-                                      const DexFile::CodeItem& disk_code_item, uint32_t offset) {
-  CodeItemDebugInfoAccessor accessor(dex_file, &disk_code_item);
+                                      const DexFile::CodeItem& disk_code_item,
+                                      uint32_t offset,
+                                      uint32_t dex_method_index) {
+  CodeItemDebugInfoAccessor accessor(dex_file, &disk_code_item, dex_method_index);
   const uint16_t registers_size = accessor.RegistersSize();
   const uint16_t ins_size = accessor.InsSize();
   const uint16_t outs_size = accessor.OutsSize();
@@ -705,7 +707,10 @@
   DebugInfoItem* debug_info = nullptr;
   if (disk_code_item != nullptr) {
     if (code_item == nullptr) {
-      code_item = CreateCodeItem(dex_file, *disk_code_item, cdii.GetMethodCodeItemOffset());
+      code_item = CreateCodeItem(dex_file,
+                                 *disk_code_item,
+                                 cdii.GetMethodCodeItemOffset(),
+                                 cdii.GetMemberIndex());
     }
     debug_info = code_item->DebugInfo();
   }
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 6797fa5..ca47b34 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -133,6 +133,7 @@
 
   uint32_t Size() const { return collection_.size(); }
   Vector& Collection() { return collection_; }
+  const Vector& Collection() const { return collection_; }
 
  protected:
   Vector collection_;
@@ -230,6 +231,8 @@
   CollectionVector<CodeItem>::Vector& CodeItems() { return code_items_.Collection(); }
   CollectionVector<ClassData>::Vector& ClassDatas() { return class_datas_.Collection(); }
 
+  const CollectionVector<ClassDef>::Vector& ClassDefs() const { return class_defs_.Collection(); }
+
   void CreateStringId(const DexFile& dex_file, uint32_t i);
   void CreateTypeId(const DexFile& dex_file, uint32_t i);
   void CreateProtoId(const DexFile& dex_file, uint32_t i);
@@ -251,8 +254,10 @@
       const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
   AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
       const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
-  CodeItem* CreateCodeItem(
-      const DexFile& dex_file, const DexFile::CodeItem& disk_code_item, uint32_t offset);
+  CodeItem* CreateCodeItem(const DexFile& dex_file,
+                           const DexFile::CodeItem& disk_code_item,
+                           uint32_t offset,
+                           uint32_t dex_method_index);
   ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
   void AddAnnotationsFromMapListSection(const DexFile& dex_file,
                                         uint32_t start_offset,
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 489a6b1..6e1cb62 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -30,25 +30,6 @@
 
 namespace art {
 
-static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
-static constexpr uint32_t kDexSectionWordAlignment = 4;
-
-static constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
-  switch (type) {
-    case DexFile::kDexTypeClassDataItem:
-    case DexFile::kDexTypeStringDataItem:
-    case DexFile::kDexTypeDebugInfoItem:
-    case DexFile::kDexTypeAnnotationItem:
-    case DexFile::kDexTypeEncodedArrayItem:
-      return alignof(uint8_t);
-
-    default:
-      // All other sections are kDexAlignedSection.
-      return kDexSectionWordAlignment;
-  }
-}
-
-
 size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
   size_t length = 0;
   if (value >= 0) {
@@ -526,69 +507,96 @@
   return offset - start;
 }
 
+uint32_t DexWriter::WriteCodeItemPostInstructionData(dex_ir::CodeItem* code_item,
+                                                     uint32_t offset,
+                                                     bool reserve_only) {
+  const uint32_t start_offset = offset;
+  if (code_item->TriesSize() != 0) {
+    // Make sure the try items are properly aligned.
+    offset = RoundUp(offset, kDexTryItemAlignment);
+    // Write try items.
+    for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
+      DexFile::TryItem disk_try_item;
+      if (!reserve_only) {
+        disk_try_item.start_addr_ = try_item->StartAddr();
+        disk_try_item.insn_count_ = try_item->InsnCount();
+        disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
+      }
+      offset += Write(&disk_try_item, sizeof(disk_try_item), offset);
+    }
+    size_t max_offset = offset;
+    // Leave offset pointing to the end of the try items.
+    UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
+    for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
+      size_t list_offset = offset + handlers->GetListOffset();
+      uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
+          handlers->GetHandlers()->size();
+      list_offset += WriteSleb128(size, list_offset);
+      for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
+        if (handler->GetTypeId() != nullptr) {
+          list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
+        }
+        list_offset += WriteUleb128(handler->GetAddress(), list_offset);
+      }
+      // TODO: Clean this up to write the handlers in address order.
+      max_offset = std::max(max_offset, list_offset);
+    }
+    offset = max_offset;
+  }
+
+  return offset - start_offset;
+}
+
+uint32_t DexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
+                                  uint32_t offset,
+                                  bool reserve_only) {
+  DCHECK(code_item != nullptr);
+  const uint32_t start_offset = offset;
+  offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
+  ProcessOffset(&offset, code_item);
+
+  StandardDexFile::CodeItem disk_code_item;
+  if (!reserve_only) {
+    disk_code_item.registers_size_ = code_item->RegistersSize();
+    disk_code_item.ins_size_ = code_item->InsSize();
+    disk_code_item.outs_size_ = code_item->OutsSize();
+    disk_code_item.tries_size_ = code_item->TriesSize();
+    disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr
+        ? 0
+        : code_item->DebugInfo()->GetOffset();
+    disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
+  }
+  // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
+  // item.
+  offset += Write(&disk_code_item,
+                  OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_),
+                  offset);
+  // Write the instructions.
+  offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+  // Write the post instruction data.
+  offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
+  return offset - start_offset;
+}
+
 uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) {
   DexLayoutSection* code_section = nullptr;
   if (!reserve_only && dex_layout_ != nullptr) {
     code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
         DexLayoutSections::SectionType::kSectionTypeCode)];
   }
-  uint16_t uint16_buffer[4] = {};
-  uint32_t uint32_buffer[2] = {};
   uint32_t start = offset;
   for (auto& code_item : header_->GetCollections().CodeItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
-    ProcessOffset(&offset, code_item.get());
-    if (!reserve_only) {
-      uint16_buffer[0] = code_item->RegistersSize();
-      uint16_buffer[1] = code_item->InsSize();
-      uint16_buffer[2] = code_item->OutsSize();
-      uint16_buffer[3] = code_item->TriesSize();
-      uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 :
-          code_item->DebugInfo()->GetOffset();
-      uint32_buffer[1] = code_item->InsnsSize();
-      // Only add the section hotness info once.
-      if (code_section != nullptr) {
-        auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
-        if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
-          code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
-              code_item->GetOffset(), code_item->GetOffset() + code_item->GetSize());
-        }
+    const size_t code_item_size = WriteCodeItem(code_item.get(), offset, reserve_only);
+    // Only add the section hotness info once.
+    if (!reserve_only && code_section != nullptr) {
+      auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
+      if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
+        code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
+            offset,
+            offset + code_item_size);
       }
     }
-    offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset);
-    offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
-    offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
-    if (code_item->TriesSize() != 0) {
-      if (code_item->InsnsSize() % 2 != 0) {
-        uint16_t padding[1] = { 0 };
-        offset += Write(padding, sizeof(uint16_t), offset);
-      }
-      uint32_t start_addr[1];
-      uint16_t insn_count_and_handler_off[2];
-      for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
-        start_addr[0] = try_item->StartAddr();
-        insn_count_and_handler_off[0] = try_item->InsnCount();
-        insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset();
-        offset += Write(start_addr, sizeof(uint32_t), offset);
-        offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset);
-      }
-      // Leave offset pointing to the end of the try items.
-      UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
-      for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
-        size_t list_offset = offset + handlers->GetListOffset();
-        uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
-            handlers->GetHandlers()->size();
-        list_offset += WriteSleb128(size, list_offset);
-        for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
-          if (handler->GetTypeId() != nullptr) {
-            list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
-          }
-          list_offset += WriteUleb128(handler->GetAddress(), list_offset);
-        }
-      }
-    }
-    // TODO: Clean this up to properly calculate the size instead of assuming it doesn't change.
-    offset = code_item->GetOffset() + code_item->GetSize();
+    offset += code_item_size;
   }
 
   if (compute_offsets_ && start != offset) {
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 92a002e..fdeb299 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -23,6 +23,7 @@
 
 #include "base/unix_file/fd_file.h"
 #include "dex/compact_dex_level.h"
+#include "dex/dex_file.h"
 #include "dex_ir.h"
 #include "mem_map.h"
 #include "os.h"
@@ -59,6 +60,25 @@
 
 class DexWriter {
  public:
+  static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
+  static constexpr uint32_t kDexSectionWordAlignment = 4;
+  static constexpr uint32_t kDexTryItemAlignment = sizeof(uint32_t);
+
+  static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
+    switch (type) {
+      case DexFile::kDexTypeClassDataItem:
+      case DexFile::kDexTypeStringDataItem:
+      case DexFile::kDexTypeDebugInfoItem:
+      case DexFile::kDexTypeAnnotationItem:
+      case DexFile::kDexTypeEncodedArrayItem:
+        return alignof(uint8_t);
+
+      default:
+        // All other sections are kDexAlignedSection.
+        return DexWriter::kDexSectionWordAlignment;
+    }
+  }
+
   DexWriter(dex_ir::Header* header,
             MemMap* mem_map,
             DexLayout* dex_layout,
@@ -77,7 +97,7 @@
   virtual ~DexWriter() {}
 
  protected:
-  void WriteMemMap();
+  virtual void WriteMemMap();
 
   size_t Write(const void* buffer, size_t length, size_t offset) WARN_UNUSED;
   size_t WriteSleb128(uint32_t value, size_t offset) WARN_UNUSED;
@@ -118,6 +138,11 @@
   uint32_t WriteMapItems(uint32_t offset, MapItemQueue* queue);
   uint32_t GenerateAndWriteMapItems(uint32_t offset);
 
+  virtual uint32_t WriteCodeItemPostInstructionData(dex_ir::CodeItem* item,
+                                                    uint32_t offset,
+                                                    bool reserve_only);
+  virtual uint32_t WriteCodeItem(dex_ir::CodeItem* item, uint32_t offset, bool reserve_only);
+
   // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
   // existing offset and use that for writing.
   void ProcessOffset(uint32_t* const offset, dex_ir::Item* item) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 000d135..a43dd07 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -34,6 +34,7 @@
 #include "android-base/stringprintf.h"
 
 #include "base/logging.h"  // For VLOG_IS_ON.
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_layout.h"
 #include "dex/dex_file_loader.h"
@@ -1923,14 +1924,16 @@
     if (options_.verify_output_) {
       std::string error_msg;
       std::string location = "memory mapped file for " + std::string(file_name);
-      std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
-                                                                         file_size,
-                                                                         location,
-                                                                         /* checksum */ 0,
-                                                                         /*oat_dex_file*/ nullptr,
-                                                                         /*verify*/ true,
-                                                                         /*verify_checksum*/ false,
-                                                                         &error_msg));
+      const ArtDexFileLoader dex_file_loader;
+      std::unique_ptr<const DexFile> output_dex_file(
+          dex_file_loader.Open(mem_map_->Begin(),
+                               file_size,
+                               location,
+                               /* checksum */ 0,
+                               /*oat_dex_file*/ nullptr,
+                               /*verify*/ true,
+                               /*verify_checksum*/ false,
+                               &error_msg));
       CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
 
       // Do IR-level comparison between input and output. This check ignores potential differences
@@ -1961,8 +1964,9 @@
   // all of which are Zip archives with "classes.dex" inside.
   const bool verify_checksum = !options_.ignore_bad_checksum_;
   std::string error_msg;
+  const ArtDexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFileLoader::Open(
+  if (!dex_file_loader.Open(
         file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 5da3b1d..3a7f9ee 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -23,6 +23,7 @@
 
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
@@ -318,12 +319,13 @@
   bool MutateDexFile(File* output_dex, const std::string& input_jar, const Mutator& mutator) {
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     std::string error_msg;
-    CHECK(DexFileLoader::Open(input_jar.c_str(),
-                              input_jar.c_str(),
-                              /*verify*/ true,
-                              /*verify_checksum*/ true,
-                              &error_msg,
-                              &dex_files)) << error_msg;
+    const ArtDexFileLoader dex_file_loader;
+    CHECK(dex_file_loader.Open(input_jar.c_str(),
+                               input_jar.c_str(),
+                               /*verify*/ true,
+                               /*verify_checksum*/ true,
+                               &error_msg,
+                               &dex_files)) << error_msg;
     EXPECT_EQ(dex_files.size(), 1u) << "Only one input dex is supported";
     for (const std::unique_ptr<const DexFile>& dex : dex_files) {
       CHECK(dex->EnableWrite()) << "Failed to enable write";
@@ -344,12 +346,13 @@
                      const std::string& dex_location) {
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     std::string error_msg;
-    bool result = DexFileLoader::Open(input_dex.c_str(),
-                                      input_dex,
-                                      /*verify*/ true,
-                                      /*verify_checksum*/ false,
-                                      &error_msg,
-                                      &dex_files);
+    const ArtDexFileLoader dex_file_loader;
+    bool result = dex_file_loader.Open(input_dex.c_str(),
+                                       input_dex,
+                                       /*verify*/ true,
+                                       /*verify_checksum*/ false,
+                                       &error_msg,
+                                       &dex_files);
 
     ASSERT_TRUE(result) << error_msg;
     ASSERT_GE(dex_files.size(), 1u);
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 556938b..1ced8ca 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 
 #include "base/logging.h"  // For InitLogging.
+#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-no_art-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
@@ -100,7 +101,7 @@
   if (pCode == nullptr || codeOffset == 0) {
     return;
   }
-  CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
+  CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
 
   // Method information.
   const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
@@ -174,7 +175,8 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  if (!dex_file_loader.Open(
         fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
     fputs(error_msg.c_str(), stderr);
     fputc('\n', stderr);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index ca8077f..f53846c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -171,7 +171,8 @@
                                     text_size,
                                     oat_file_->BssSize(),
                                     oat_file_->BssMethodsOffset(),
-                                    oat_file_->BssRootsOffset());
+                                    oat_file_->BssRootsOffset(),
+                                    oat_file_->VdexSize());
     builder_->WriteDynamicSection();
 
     const OatHeader& oat_header = oat_file_->GetOatHeader();
@@ -717,7 +718,6 @@
     }
 
     vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
-                         vdex_file->GetQuickeningInfo(),
                          /* decompile_return_instruction */ true);
 
     *dex_files = std::move(tmp_dex_files);
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index da7d60a..dcc834a 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -30,6 +30,7 @@
  */
 
 #include "fixed_up_dex_file.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 
@@ -62,8 +63,7 @@
   if (vdex == nullptr) {
     return;
   }
-  art::VdexFile::UnquickenDexFile(
-      new_dex_file, vdex->GetQuickeningInfo(), /* decompile_return_instruction */true);
+  vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
 }
 
 std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) {
@@ -72,7 +72,8 @@
   data.resize(original.Size());
   memcpy(data.data(), original.Begin(), original.Size());
   std::string error;
-  std::unique_ptr<const art::DexFile> new_dex_file(art::DexFileLoader::Open(
+  const art::ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open(
       data.data(),
       data.size(),
       /*location*/"Unquickening_dexfile.dex",
@@ -103,7 +104,7 @@
     // Overwrite the dex file stored in data with the new result.
     data.clear();
     data.insert(data.end(), mem_map->Begin(), mem_map->Begin() + dex_file_size);
-    new_dex_file = art::DexFileLoader::Open(
+    new_dex_file = dex_file_loader.Open(
         data.data(),
         data.size(),
         /*location*/"Unquickening_dexfile.dex",
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index f9eb008..b3f5c18 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -42,6 +42,7 @@
 #include "class_linker.h"
 #include "class_table-inl.h"
 #include "common_throws.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_annotations.h"
 #include "dex/dex_file_loader.h"
 #include "events-inl.h"
@@ -107,12 +108,13 @@
   }
   uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
   std::string map_name = map->GetName();
-  std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map_name,
-                                                                        checksum,
-                                                                        std::move(map),
-                                                                        /*verify*/true,
-                                                                        /*verify_checksum*/true,
-                                                                        &error_msg));
+  const art::ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map_name,
+                                                                    checksum,
+                                                                    std::move(map),
+                                                                    /*verify*/true,
+                                                                    /*verify_checksum*/true,
+                                                                    &error_msg));
   if (dex_file.get() == nullptr) {
     LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg;
     art::ThrowClassFormatError(nullptr,
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 6194d1e..717b2ba 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -43,6 +43,7 @@
 #include "base/stringpiece.h"
 #include "class_linker-inl.h"
 #include "debugger.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_file_types.h"
@@ -426,12 +427,13 @@
     return ERR(INVALID_CLASS_FORMAT);
   }
   uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
-  std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map->GetName(),
-                                                                        checksum,
-                                                                        std::move(map),
-                                                                        /*verify*/true,
-                                                                        /*verify_checksum*/true,
-                                                                        error_msg_));
+  const art::ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map->GetName(),
+                                                                    checksum,
+                                                                    std::move(map),
+                                                                    /*verify*/true,
+                                                                    /*verify_checksum*/true,
+                                                                    error_msg_));
   if (dex_file.get() == nullptr) {
     os << "Unable to load modified dex file for " << def.GetName() << ": " << *error_msg_;
     *error_msg_ = os.str();
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index 9d5f4ea..cbb7b53 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -38,6 +38,7 @@
 #include "base/enums.h"
 #include "base/macros.h"
 #include "class_linker.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "jni_internal.h"
@@ -227,7 +228,8 @@
 
   std::string error_msg;
   std::vector<std::unique_ptr<const art::DexFile>> dex_files;
-  if (!art::DexFileLoader::Open(
+  const art::ArtDexFileLoader dex_file_loader;
+  if (!dex_file_loader.Open(
         segment, segment, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)) {
     LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg;
     return ERR(ILLEGAL_ARGUMENT);
diff --git a/profman/profman.cc b/profman/profman.cc
index c4216fa..9f3e3b6 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -39,6 +39,7 @@
 #include "base/unix_file/fd_file.h"
 #include "boot_image_profile.h"
 #include "bytecode_utils.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-inl.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
@@ -329,25 +330,26 @@
     static constexpr bool kVerifyChecksum = true;
     for (size_t i = 0; i < dex_locations_.size(); ++i) {
       std::string error_msg;
+      const ArtDexFileLoader dex_file_loader;
       std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
       if (use_apk_fd_list) {
-        if (DexFileLoader::OpenZip(apks_fd_[i],
-                                   dex_locations_[i],
-                                   /* verify */ true,
-                                   kVerifyChecksum,
-                                   &error_msg,
-                                   &dex_files_for_location)) {
+        if (dex_file_loader.OpenZip(apks_fd_[i],
+                                    dex_locations_[i],
+                                    /* verify */ true,
+                                    kVerifyChecksum,
+                                    &error_msg,
+                                    &dex_files_for_location)) {
         } else {
           LOG(WARNING) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
           continue;
         }
       } else {
-        if (DexFileLoader::Open(apk_files_[i].c_str(),
-                                dex_locations_[i],
-                                /* verify */ true,
-                                kVerifyChecksum,
-                                &error_msg,
-                                &dex_files_for_location)) {
+        if (dex_file_loader.Open(apk_files_[i].c_str(),
+                                 dex_locations_[i],
+                                 /* verify */ true,
+                                 kVerifyChecksum,
+                                 &error_msg,
+                                 &dex_files_for_location)) {
         } else {
           LOG(WARNING) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
           continue;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 2657f4f..2e34baf 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -21,6 +21,71 @@
 JIT_DEBUG_REGISTER_CODE_LDFLAGS = ["-Wl,--keep-unique,__jit_debug_register_code"]
 
 cc_defaults {
+    name: "libdexfile_defaults",
+    defaults: ["art_defaults"],
+    host_supported: true,
+    srcs: [
+        "dex/compact_dex_debug_info.cc",
+        "dex/compact_dex_file.cc",
+        "dex/dex_file.cc",
+        "dex/dex_file_exception_helpers.cc",
+        "dex/dex_file_loader.cc",
+        "dex/dex_file_tracking_registrar.cc",
+        "dex/dex_file_verifier.cc",
+        "dex/dex_instruction.cc",
+        "dex/standard_dex_file.cc",
+        "utf.cc",
+        "utils.cc",
+    ],
+
+    target: {
+        android: {
+            shared_libs: [
+                "libutils",
+            ],
+            static_libs: [
+                "libz",
+                "libbase",
+            ],
+        },
+        host: {
+            shared_libs: [
+                "libz",
+            ],
+        },
+    },
+    generated_sources: ["art_operator_srcs"],
+    // asm_support_gen.h (used by asm_support.h) is generated with cpp-define-generator
+    generated_headers: ["cpp-define-generator-asm-support"],
+    // export our headers so the libart-gtest targets can use it as well.
+    export_generated_headers: ["cpp-define-generator-asm-support"],
+    include_dirs: [
+        "external/icu/icu4c/source/common",
+        "external/zlib",
+    ],
+    shared_libs: [
+        "liblog",
+        // For common macros.
+        "libbase",
+    ],
+    export_include_dirs: ["."],
+    // ART's macros.h depends on libbase's macros.h.
+    // Note: runtime_options.h depends on cmdline. But we don't really want to export this
+    //       generically. dex2oat takes care of it itself.
+    export_shared_lib_headers: ["libbase"],
+}
+
+art_cc_library {
+    name: "libdexfile",
+    defaults: ["libdexfile_defaults"],
+    // Leave the symbols in the shared library so that stack unwinders can
+    // produce meaningful name resolution.
+    strip: {
+        keep_symbols: true,
+    },
+}
+
+cc_defaults {
     name: "libart_defaults",
     defaults: ["art_defaults"],
     host_supported: true,
@@ -56,12 +121,14 @@
         "common_throws.cc",
         "compiler_filter.cc",
         "debugger.cc",
+        "dex/compact_dex_debug_info.cc",
         "dex/compact_dex_file.cc",
         "dex/dex_file.cc",
         "dex/dex_file_annotations.cc",
         "dex/dex_file_exception_helpers.cc",
         "dex/dex_file_layout.cc",
         "dex/dex_file_loader.cc",
+        "dex/art_dex_file_loader.cc",
         "dex/dex_file_tracking_registrar.cc",
         "dex/dex_file_verifier.cc",
         "dex/dex_instruction.cc",
@@ -572,6 +639,7 @@
         "class_table_test.cc",
         "compiler_filter_test.cc",
         "dex/code_item_accessors_test.cc",
+        "dex/compact_dex_debug_info_test.cc",
         "dex/compact_dex_file_test.cc",
         "dex/dex_file_test.cc",
         "dex/dex_file_verifier_test.cc",
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 44a5dde..96468bb 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -562,14 +562,14 @@
   return true;
 }
 
-const uint8_t* ArtMethod::GetQuickenedInfo() {
+ArrayRef<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 ArrayRef<const uint8_t>();
   }
-  return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
-      dex_file, GetCodeItemOffset());
+  return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(dex_file,
+                                                                       GetDexMethodIndex());
 }
 
 const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index c4a586e..cd06354 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/enums.h"
@@ -662,7 +663,7 @@
     return hotness_count_;
   }
 
-  const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
+  ArrayRef<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.
diff --git a/runtime/base/bit_string.h b/runtime/base/bit_string.h
index bfbe8ea..7d9fb70 100644
--- a/runtime/base/bit_string.h
+++ b/runtime/base/bit_string.h
@@ -114,13 +114,13 @@
 /**
  *                           BitString
  *
- * lsb (least significant bit)                              msb
- *  +------------+------------+------------+-----+------------+
- *  |            |            |            |     |            |
- *  |   Char0    |    Char1   |   Char2    | ... |   CharN    |
- *  |            |            |            |     |            |
- *  +------------+------------+------------+-----+------------+
- *   <- len[0] -> <- len[1] -> <- len[2] ->  ...  <- len[N] ->
+ * MSB (most significant bit)                                LSB
+ *  +------------+-----+------------+------------+------------+
+ *  |            |     |            |            |            |
+ *  |   CharN    | ... |    Char2   |   Char1    |   Char0    |
+ *  |            |     |            |            |            |
+ *  +------------+-----+------------+------------+------------+
+ *   <- len[N] ->  ...  <- len[2] -> <- len[1] -> <- len[0] ->
  *
  * Stores up to "N+1" characters in a subset of a machine word. Each character has a different
  * bitlength, as defined by len[pos]. This BitString can be nested inside of a BitStruct
@@ -145,7 +145,7 @@
   // As this is meant to be used only with "SubtypeCheckInfo",
   // the bitlengths and the maximum string length is tuned by maximizing the coverage of "Assigned"
   // bitstrings for instance-of and check-cast targets during Optimizing compilation.
-  static constexpr size_t kBitSizeAtPosition[] = {12, 3, 8};          // len[] from header docs.
+  static constexpr size_t kBitSizeAtPosition[] = {12, 4, 11};         // len[] from header docs.
   static constexpr size_t kCapacity = arraysize(kBitSizeAtPosition);  // MaxBitstringLen above.
 
   // How many bits are needed to represent BitString[0..position)?
@@ -165,8 +165,7 @@
   // (e.g. to use with BitField{Insert,Extract,Clear}.)
   static constexpr size_t GetLsbForPosition(size_t position) {
     DCHECK_GE(kCapacity, position);
-    constexpr size_t kMaximumBitLength = GetBitLengthTotalAtPosition(kCapacity);
-    return kMaximumBitLength - GetBitLengthTotalAtPosition(position + 1u);
+    return GetBitLengthTotalAtPosition(position);
   }
 
   // How many bits are needed for a BitStringChar at the position?
@@ -183,9 +182,7 @@
   BitStringChar operator[](size_t idx) const {
     DCHECK_LT(idx, kCapacity);
 
-    StorageType data =
-        BitFieldExtract(storage_,
-                        GetLsbForPosition(idx), kBitSizeAtPosition[idx]);
+    StorageType data = BitFieldExtract(storage_, GetLsbForPosition(idx), kBitSizeAtPosition[idx]);
 
     return BitStringChar(data, kBitSizeAtPosition[idx]);
   }
@@ -259,17 +256,10 @@
     DCHECK_GE(kCapacity, end);
     BitString copy = *this;
 
-    size_t bit_size = 0;
-    for (size_t idx = end; idx < kCapacity; ++idx) {
-      bit_size += kBitSizeAtPosition[idx];
-    }
-    // TODO: precompute above table.
-
-    if (bit_size > 0) {
-      StorageType data =
-          BitFieldClear(copy.storage_,
-                        GetLsbForPosition(kCapacity),
-                        bit_size);
+    if (end < kCapacity) {
+      size_t lsb = GetLsbForPosition(end);
+      size_t bit_size = GetLsbForPosition(kCapacity) - lsb;
+      StorageType data = BitFieldClear(copy.storage_, lsb, bit_size);
       copy.storage_ = data;
     }
 
diff --git a/runtime/base/bit_string_test.cc b/runtime/base/bit_string_test.cc
index 96aa154..23274e3 100644
--- a/runtime/base/bit_string_test.cc
+++ b/runtime/base/bit_string_test.cc
@@ -65,7 +65,7 @@
   return uint_value;
 }
 
-// Make max bitstring, e.g. BitString[4095,7,255] for {12,3,8}
+// Make max bitstring, e.g. BitString[4095,15,2047] for {12,4,11}
 template <size_t kCount = BitString::kCapacity>
 BitString MakeBitStringMax() {
   BitString bs{};
@@ -87,15 +87,14 @@
 #define EXPECT_BITSTRING_STR(expected_str, actual_value)                       \
   EXPECT_STREQ((expected_str), Stringify((actual_value)).c_str())
 
+// TODO: Consider removing this test, it's kind of replicating the logic in GetLsbForPosition().
 TEST(InstanceOfBitString, GetLsbForPosition) {
   ASSERT_LE(3u, BitString::kCapacity);
   // Test will fail if kCapacity is not at least 3. Update it.
-  EXPECT_EQ(0u, BitString::GetLsbForPosition(BitString::kCapacity - 1u));
-  EXPECT_EQ(BitString::kBitSizeAtPosition[BitString::kCapacity - 1u],
-            BitString::GetLsbForPosition(BitString::kCapacity - 2u));
-  EXPECT_EQ(BitString::kBitSizeAtPosition[BitString::kCapacity - 1u] +
-                BitString::kBitSizeAtPosition[BitString::kCapacity - 2u],
-            BitString::GetLsbForPosition(BitString::kCapacity - 3u));
+  EXPECT_EQ(0u, BitString::GetLsbForPosition(0u));
+  EXPECT_EQ(BitString::kBitSizeAtPosition[0u], BitString::GetLsbForPosition(1u));
+  EXPECT_EQ(BitString::kBitSizeAtPosition[0u] + BitString::kBitSizeAtPosition[1u],
+            BitString::GetLsbForPosition(2u));
 }
 
 TEST(InstanceOfBitString, ToString) {
@@ -126,8 +125,8 @@
   // Each maximal value should be tested here for each position.
   uint32_t max_bitstring_ints[] = {
       MaxInt<uint32_t>(12),
-      MaxInt<uint32_t>(3),
-      MaxInt<uint32_t>(8),
+      MaxInt<uint32_t>(4),
+      MaxInt<uint32_t>(11),
   };
 
   // Update tests if changing the tuning values above.
@@ -151,14 +150,13 @@
 }
 
 TEST(InstanceOfBitString, MemoryRepresentation) {
-  // Verify that the lower positions are stored in more significant bits.
+  // Verify that the lower positions are stored in less significant bits.
   BitString bs = MakeBitString({MaxForPos<0>(), MaxForPos<1>()});
   BitString::StorageType as_int = static_cast<BitString::StorageType>(bs);
 
-  // Below tests assumes the capacity is 3. Update if it this changes.
-  ASSERT_EQ(3u, BitString::kCapacity);
-  EXPECT_EQ(MaxForPos<0>()  << (BitString::kBitSizeAtPosition[2] + BitString::kBitSizeAtPosition[1]) |
-               (MaxForPos<1>() << BitString::kBitSizeAtPosition[2]),
+  // Below tests assumes the capacity is at least 3.
+  ASSERT_LE(3u, BitString::kCapacity);
+  EXPECT_EQ((MaxForPos<0>() << 0) | (MaxForPos<1>() << BitString::kBitSizeAtPosition[0]),
             as_int);
 }
 
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 34cddbf..d2a99f1 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -46,10 +46,14 @@
 constexpr int CLZ(T x) {
   static_assert(std::is_integral<T>::value, "T must be integral");
   static_assert(std::is_unsigned<T>::value, "T must be unsigned");
-  static_assert(sizeof(T) <= sizeof(long long),  // NOLINT [runtime/int] [4]
-                "T too large, must be smaller than long long");
+  static_assert(std::numeric_limits<T>::radix == 2, "Unexpected radix!");
+  static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t),
+                "Unsupported sizeof(T)");
   DCHECK_NE(x, 0u);
-  return (sizeof(T) == sizeof(uint32_t)) ? __builtin_clz(x) : __builtin_clzll(x);
+  constexpr bool is_64_bit = (sizeof(T) == sizeof(uint64_t));
+  constexpr size_t adjustment =
+      is_64_bit ? 0u : std::numeric_limits<uint32_t>::digits - std::numeric_limits<T>::digits;
+  return is_64_bit ? __builtin_clzll(x) : __builtin_clz(x) - adjustment;
 }
 
 // Similar to CLZ except that on zero input it returns bitwidth and supports signed integers.
@@ -65,10 +69,10 @@
   static_assert(std::is_integral<T>::value, "T must be integral");
   // It is not unreasonable to ask for trailing zeros in a negative number. As such, do not check
   // that T is an unsigned type.
-  static_assert(sizeof(T) <= sizeof(long long),  // NOLINT [runtime/int] [4]
-                "T too large, must be smaller than long long");
+  static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t),
+                "Unsupported sizeof(T)");
   DCHECK_NE(x, static_cast<T>(0));
-  return (sizeof(T) == sizeof(uint32_t)) ? __builtin_ctz(x) : __builtin_ctzll(x);
+  return (sizeof(T) == sizeof(uint64_t)) ? __builtin_ctzll(x) : __builtin_ctz(x);
 }
 
 // Similar to CTZ except that on zero input it returns bitwidth and supports signed integers.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 3ec5335..e646520 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"
 #include "class_linker.h"
 #include "class_loader_utils.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "handle_scope-inl.h"
@@ -203,6 +204,7 @@
   // We may get resource-only apks which we cannot load.
   // TODO(calin): Refine the dex opening interface to be able to tell if an archive contains
   // no dex files. So that we can distinguish the real failures...
+  const ArtDexFileLoader dex_file_loader;
   for (ClassLoaderInfo& info : class_loader_chain_) {
     size_t opened_dex_files_index = info.opened_dex_files.size();
     for (const std::string& cp_elem : info.classpath) {
@@ -215,12 +217,12 @@
       std::string error_msg;
       // When opening the dex files from the context we expect their checksum to match their
       // contents. So pass true to verify_checksum.
-      if (!DexFileLoader::Open(location.c_str(),
-                               location.c_str(),
-                               Runtime::Current()->IsVerificationEnabled(),
-                               /*verify_checksum*/ true,
-                               &error_msg,
-                               &info.opened_dex_files)) {
+      if (!dex_file_loader.Open(location.c_str(),
+                                location.c_str(),
+                                Runtime::Current()->IsVerificationEnabled(),
+                                /*verify_checksum*/ true,
+                                &error_msg,
+                                &info.opened_dex_files)) {
         // If we fail to open the dex file because it's been stripped, try to open the dex file
         // from its corresponding oat file.
         // This could happen when we need to recompile a pre-build whose dex code has been stripped.
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 96d660f..39dbebf 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -35,6 +35,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "compiler_callbacks.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "gc/heap.h"
@@ -375,7 +376,8 @@
   std::string error_msg;
   MemMap::Init();
   static constexpr bool kVerifyChecksum = true;
-  if (!DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  if (!dex_file_loader.Open(
         location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
     LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
     UNREACHABLE();
@@ -574,12 +576,13 @@
   std::string filename = GetTestDexFileName(name);
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
+  const ArtDexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  bool success = DexFileLoader::Open(filename.c_str(),
-                                     filename.c_str(),
-                                     /* verify */ true,
-                                     kVerifyChecksum,
-                                     &error_msg, &dex_files);
+  bool success = dex_file_loader.Open(filename.c_str(),
+                                      filename.c_str(),
+                                      /* verify */ true,
+                                      kVerifyChecksum,
+                                      &error_msg, &dex_files);
   CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
   for (auto& dex_file : dex_files) {
     CHECK_EQ(PROT_READ, dex_file->GetPermissions());
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
new file mode 100644
index 0000000..282b282
--- /dev/null
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -0,0 +1,465 @@
+/*
+ * 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 "art_dex_file_loader.h"
+
+#include <sys/mman.h>  // For the PROT_* and MAP_* constants.
+#include <sys/stat.h>
+
+#include "android-base/stringprintf.h"
+
+#include "base/file_magic.h"
+#include "base/stl_util.h"
+#include "base/systrace.h"
+#include "base/unix_file/fd_file.h"
+#include "compact_dex_file.h"
+#include "dex_file.h"
+#include "dex_file_verifier.h"
+#include "standard_dex_file.h"
+#include "zip_archive.h"
+
+namespace art {
+
+namespace {
+
+class MemMapContainer : public DexFileContainer {
+ public:
+  explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { }
+  virtual ~MemMapContainer() OVERRIDE { }
+
+  int GetPermissions() OVERRIDE {
+    if (mem_map_.get() == nullptr) {
+      return 0;
+    } else {
+      return mem_map_->GetProtect();
+    }
+  }
+
+  bool IsReadOnly() OVERRIDE {
+    return GetPermissions() == PROT_READ;
+  }
+
+  bool EnableWrite() OVERRIDE {
+    CHECK(IsReadOnly());
+    if (mem_map_.get() == nullptr) {
+      return false;
+    } else {
+      return mem_map_->Protect(PROT_READ | PROT_WRITE);
+    }
+  }
+
+  bool DisableWrite() OVERRIDE {
+    CHECK(!IsReadOnly());
+    if (mem_map_.get() == nullptr) {
+      return false;
+    } else {
+      return mem_map_->Protect(PROT_READ);
+    }
+  }
+
+ private:
+  std::unique_ptr<MemMap> mem_map_;
+  DISALLOW_COPY_AND_ASSIGN(MemMapContainer);
+};
+
+}  // namespace
+
+using android::base::StringPrintf;
+
+static constexpr OatDexFile* kNoOatDexFile = nullptr;
+
+
+bool ArtDexFileLoader::GetMultiDexChecksums(const char* filename,
+                                            std::vector<uint32_t>* checksums,
+                                            std::string* error_msg,
+                                            int zip_fd) const {
+  CHECK(checksums != nullptr);
+  uint32_t magic;
+
+  File fd;
+  if (zip_fd != -1) {
+     if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
+       fd = File(zip_fd, false /* check_usage */);
+     }
+  } else {
+    fd = OpenAndReadMagic(filename, &magic, error_msg);
+  }
+  if (fd.Fd() == -1) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  if (IsZipMagic(magic)) {
+    std::unique_ptr<ZipArchive> zip_archive(
+        ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
+    if (zip_archive.get() == nullptr) {
+      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
+                                error_msg->c_str());
+      return false;
+    }
+
+    uint32_t i = 0;
+    std::string zip_entry_name = GetMultiDexClassesDexName(i++);
+    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+    if (zip_entry.get() == nullptr) {
+      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+          zip_entry_name.c_str(), error_msg->c_str());
+      return false;
+    }
+
+    do {
+      checksums->push_back(zip_entry->GetCrc32());
+      zip_entry_name = GetMultiDexClassesDexName(i++);
+      zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+    } while (zip_entry.get() != nullptr);
+    return true;
+  }
+  if (IsMagicValid(magic)) {
+    std::unique_ptr<const DexFile> dex_file(
+        OpenFile(fd.Release(), filename, false, false, error_msg));
+    if (dex_file == nullptr) {
+      return false;
+    }
+    checksums->push_back(dex_file->GetHeader().checksum_);
+    return true;
+  }
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return false;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base,
+                                                      size_t size,
+                                                      const std::string& location,
+                                                      uint32_t location_checksum,
+                                                      const OatDexFile* oat_dex_file,
+                                                      bool verify,
+                                                      bool verify_checksum,
+                                                      std::string* error_msg) const {
+  ScopedTrace trace(std::string("Open dex file from RAM ") + location);
+  return OpenCommon(base,
+                    size,
+                    location,
+                    location_checksum,
+                    oat_dex_file,
+                    verify,
+                    verify_checksum,
+                    error_msg,
+                    /*container*/ nullptr,
+                    /*verify_result*/ nullptr);
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& location,
+                                                      uint32_t location_checksum,
+                                                      std::unique_ptr<MemMap> map,
+                                                      bool verify,
+                                                      bool verify_checksum,
+                                                      std::string* error_msg) const {
+  ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
+  CHECK(map.get() != nullptr);
+
+  if (map->Size() < sizeof(DexFile::Header)) {
+    *error_msg = StringPrintf(
+        "DexFile: failed to open dex file '%s' that is too short to have a header",
+        location.c_str());
+    return nullptr;
+  }
+
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 location_checksum,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg,
+                                                 new MemMapContainer(std::move(map)),
+                                                 /*verify_result*/ nullptr);
+  return dex_file;
+}
+
+bool ArtDexFileLoader::Open(const char* filename,
+                            const std::string& location,
+                            bool verify,
+                            bool verify_checksum,
+                            std::string* error_msg,
+                            std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
+  uint32_t magic;
+  File fd = OpenAndReadMagic(filename, &magic, error_msg);
+  if (fd.Fd() == -1) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  if (IsZipMagic(magic)) {
+    return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
+  }
+  if (IsMagicValid(magic)) {
+    std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
+                                                     location,
+                                                     verify,
+                                                     verify_checksum,
+                                                     error_msg));
+    if (dex_file.get() != nullptr) {
+      dex_files->push_back(std::move(dex_file));
+      return true;
+    } else {
+      return false;
+    }
+  }
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return false;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenDex(int fd,
+                                                         const std::string& location,
+                                                         bool verify,
+                                                         bool verify_checksum,
+                                                         std::string* error_msg) const {
+  ScopedTrace trace("Open dex file " + std::string(location));
+  return OpenFile(fd, location, verify, verify_checksum, error_msg);
+}
+
+bool ArtDexFileLoader::OpenZip(int fd,
+                               const std::string& location,
+                               bool verify,
+                               bool verify_checksum,
+                               std::string* error_msg,
+                               std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+  ScopedTrace trace("Dex file open Zip " + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
+  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
+  if (zip_archive.get() == nullptr) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  return OpenAllDexFilesFromZip(
+      *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd,
+                                                          const std::string& location,
+                                                          bool verify,
+                                                          bool verify_checksum,
+                                                          std::string* error_msg) const {
+  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+  CHECK(!location.empty());
+  std::unique_ptr<MemMap> map;
+  {
+    File delayed_close(fd, /* check_usage */ false);
+    struct stat sbuf;
+    memset(&sbuf, 0, sizeof(sbuf));
+    if (fstat(fd, &sbuf) == -1) {
+      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
+                                strerror(errno));
+      return nullptr;
+    }
+    if (S_ISDIR(sbuf.st_mode)) {
+      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+      return nullptr;
+    }
+    size_t length = sbuf.st_size;
+    map.reset(MemMap::MapFile(length,
+                              PROT_READ,
+                              MAP_PRIVATE,
+                              fd,
+                              0,
+                              /*low_4gb*/false,
+                              location.c_str(),
+                              error_msg));
+    if (map == nullptr) {
+      DCHECK(!error_msg->empty());
+      return nullptr;
+    }
+  }
+
+  if (map->Size() < sizeof(DexFile::Header)) {
+    *error_msg = StringPrintf(
+        "DexFile: failed to open dex file '%s' that is too short to have a header",
+        location.c_str());
+    return nullptr;
+  }
+
+  const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
+
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 dex_header->checksum_,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg,
+                                                 new MemMapContainer(std::move(map)),
+                                                 /*verify_result*/ nullptr);
+
+  return dex_file;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip(
+    const ZipArchive& zip_archive,
+    const char* entry_name,
+    const std::string& location,
+    bool verify,
+    bool verify_checksum,
+    std::string* error_msg,
+    ZipOpenErrorCode* error_code) const {
+  ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
+  CHECK(!location.empty());
+  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
+  if (zip_entry == nullptr) {
+    *error_code = ZipOpenErrorCode::kEntryNotFound;
+    return nullptr;
+  }
+  if (zip_entry->GetUncompressedLength() == 0) {
+    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
+    *error_code = ZipOpenErrorCode::kDexFileError;
+    return nullptr;
+  }
+
+  std::unique_ptr<MemMap> map;
+  if (zip_entry->IsUncompressed()) {
+    if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
+      // Do not mmap unaligned ZIP entries because
+      // doing so would fail dex verification which requires 4 byte alignment.
+      LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+                   << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
+                   << "Falling back to extracting file.";
+    } else {
+      // Map uncompressed files within zip as file-backed to avoid a dirty copy.
+      map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
+      if (map == nullptr) {
+        LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+                     << "is your ZIP file corrupted? Falling back to extraction.";
+        // Try again with Extraction which still has a chance of recovery.
+      }
+    }
+  }
+
+  if (map == nullptr) {
+    // Default path for compressed ZIP entries,
+    // and fallback for stored ZIP entries.
+    map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
+  }
+
+  if (map == nullptr) {
+    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
+                              error_msg->c_str());
+    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+    return nullptr;
+  }
+  VerifyResult verify_result;
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 zip_entry->GetCrc32(),
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg,
+                                                 new MemMapContainer(std::move(map)),
+                                                 &verify_result);
+  if (dex_file == nullptr) {
+    if (verify_result == VerifyResult::kVerifyNotAttempted) {
+      *error_code = ZipOpenErrorCode::kDexFileError;
+    } else {
+      *error_code = ZipOpenErrorCode::kVerifyError;
+    }
+    return nullptr;
+  }
+  if (!dex_file->DisableWrite()) {
+    *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
+    return nullptr;
+  }
+  CHECK(dex_file->IsReadOnly()) << location;
+  if (verify_result != VerifyResult::kVerifySucceeded) {
+    *error_code = ZipOpenErrorCode::kVerifyError;
+    return nullptr;
+  }
+  *error_code = ZipOpenErrorCode::kNoError;
+  return dex_file;
+}
+
+// Technically we do not have a limitation with respect to the number of dex files that can be in a
+// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
+// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
+// seems an excessive number.
+static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
+
+bool ArtDexFileLoader::OpenAllDexFilesFromZip(
+    const ZipArchive& zip_archive,
+    const std::string& location,
+    bool verify,
+    bool verify_checksum,
+    std::string* error_msg,
+    std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+  ScopedTrace trace("Dex file open from Zip " + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
+  ZipOpenErrorCode error_code;
+  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                kClassesDex,
+                                                                location,
+                                                                verify,
+                                                                verify_checksum,
+                                                                error_msg,
+                                                                &error_code));
+  if (dex_file.get() == nullptr) {
+    return false;
+  } else {
+    // Had at least classes.dex.
+    dex_files->push_back(std::move(dex_file));
+
+    // Now try some more.
+
+    // We could try to avoid std::string allocations by working on a char array directly. As we
+    // do not expect a lot of iterations, this seems too involved and brittle.
+
+    for (size_t i = 1; ; ++i) {
+      std::string name = GetMultiDexClassesDexName(i);
+      std::string fake_location = GetMultiDexLocation(i, location.c_str());
+      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                         name.c_str(),
+                                                                         fake_location,
+                                                                         verify,
+                                                                         verify_checksum,
+                                                                         error_msg,
+                                                                         &error_code));
+      if (next_dex_file.get() == nullptr) {
+        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+          LOG(WARNING) << "Zip open failed: " << *error_msg;
+        }
+        break;
+      } else {
+        dex_files->push_back(std::move(next_dex_file));
+      }
+
+      if (i == kWarnOnManyDexFilesThreshold) {
+        LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
+                     << " dex files. Please consider coalescing and shrinking the number to "
+                        " avoid runtime overhead.";
+      }
+
+      if (i == std::numeric_limits<size_t>::max()) {
+        LOG(ERROR) << "Overflow in number of dex files!";
+        break;
+      }
+    }
+
+    return true;
+  }
+}
+
+}  // namespace art
diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h
new file mode 100644
index 0000000..a6191d9
--- /dev/null
+++ b/runtime/dex/art_dex_file_loader.h
@@ -0,0 +1,125 @@
+/*
+ * 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_DEX_ART_DEX_FILE_LOADER_H_
+#define ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "dex_file_loader.h"
+#include "base/macros.h"
+
+namespace art {
+
+class DexFile;
+class DexFileContainer;
+class MemMap;
+class OatDexFile;
+class ZipArchive;
+
+// Class that is used to open dex files and deal with corresponding multidex and location logic.
+class ArtDexFileLoader : public DexFileLoader {
+ public:
+  virtual ~ArtDexFileLoader() { }
+
+  // Returns the checksums of a file for comparison with GetLocationChecksum().
+  // For .dex files, this is the single header checksum.
+  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+  // each additional multidex entry classes2.dex, classes3.dex, etc.
+  // If a valid zip_fd is provided the file content will be read directly from
+  // the descriptor and `filename` will be used as alias for error logging. If
+  // zip_fd is -1, the method will try to open the `filename` and read the
+  // content from it.
+  // Return true if the checksums could be found, false otherwise.
+  bool GetMultiDexChecksums(const char* filename,
+                            std::vector<uint32_t>* checksums,
+                            std::string* error_msg,
+                            int zip_fd = -1) const OVERRIDE;
+
+  // Opens .dex file, backed by existing memory
+  std::unique_ptr<const DexFile> Open(const uint8_t* base,
+                                      size_t size,
+                                      const std::string& location,
+                                      uint32_t location_checksum,
+                                      const OatDexFile* oat_dex_file,
+                                      bool verify,
+                                      bool verify_checksum,
+                                      std::string* error_msg) const OVERRIDE;
+
+  // Opens .dex file that has been memory-mapped by the caller.
+  std::unique_ptr<const DexFile> Open(const std::string& location,
+                                      uint32_t location_checkum,
+                                      std::unique_ptr<MemMap> mem_map,
+                                      bool verify,
+                                      bool verify_checksum,
+                                      std::string* error_msg) const OVERRIDE;
+
+  // Opens all .dex files found in the file, guessing the container format based on file extension.
+  bool Open(const char* filename,
+            const std::string& location,
+            bool verify,
+            bool verify_checksum,
+            std::string* error_msg,
+            std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+
+  // Open a single dex file from an fd. This function closes the fd.
+  std::unique_ptr<const DexFile> OpenDex(int fd,
+                                         const std::string& location,
+                                         bool verify,
+                                         bool verify_checksum,
+                                         std::string* error_msg) const OVERRIDE;
+
+  // Opens dex files from within a .jar, .zip, or .apk file
+  bool OpenZip(int fd,
+               const std::string& location,
+               bool verify,
+               bool verify_checksum,
+               std::string* error_msg,
+               std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+
+ private:
+  std::unique_ptr<const DexFile> OpenFile(int fd,
+                                          const std::string& location,
+                                          bool verify,
+                                          bool verify_checksum,
+                                          std::string* error_msg) const OVERRIDE;
+
+  // Open all classesXXX.dex files from a zip archive.
+  bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                              const std::string& location,
+                              bool verify,
+                              bool verify_checksum,
+                              std::string* error_msg,
+                              std::vector<std::unique_ptr<const DexFile>>* dex_files)
+      const OVERRIDE;
+
+  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+  // return.
+  std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+                                                       const char* entry_name,
+                                                       const std::string& location,
+                                                       bool verify,
+                                                       bool verify_checksum,
+                                                       std::string* error_msg,
+                                                       ZipOpenErrorCode* error_code) const OVERRIDE;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h
index 2792dc0..63fd120 100644
--- a/runtime/dex/code_item_accessors-inl.h
+++ b/runtime/dex/code_item_accessors-inl.h
@@ -34,15 +34,9 @@
     : CodeItemDataAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
 
 inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
-    : CodeItemDebugInfoAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
-
-inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile& dex_file,
-                                                            const DexFile::CodeItem* code_item) {
-  if (code_item == nullptr) {
-    return;
-  }
-  Init(dex_file, code_item, OatFile::GetDebugInfoOffset(dex_file, code_item->debug_info_off_));
-}
+    : CodeItemDebugInfoAccessor(*method->GetDexFile(),
+                                method->GetCodeItem(),
+                                method->GetDexMethodIndex()) {}
 
 }  // namespace art
 
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index baea856..aaa86d4 100644
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -146,22 +146,28 @@
 
 inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
                                             const DexFile::CodeItem* code_item,
-                                            uint32_t debug_info_offset) {
+                                            uint32_t dex_method_index) {
+  if (code_item == nullptr) {
+    return;
+  }
   dex_file_ = &dex_file;
-  debug_info_offset_ = debug_info_offset;
   if (dex_file.IsCompactDexFile()) {
-    Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+    Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
   } else {
     DCHECK(dex_file.IsStandardDexFile());
     Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
   }
 }
 
-inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item,
+                                            uint32_t dex_method_index) {
+  debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
+      dex_method_index);
   CodeItemDataAccessor::Init(code_item);
 }
 
 inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+  debug_info_offset_ = code_item.debug_info_off_;
   CodeItemDataAccessor::Init(code_item);
 }
 
diff --git a/runtime/dex/code_item_accessors.h b/runtime/dex/code_item_accessors.h
index b5a6957..66531f9 100644
--- a/runtime/dex/code_item_accessors.h
+++ b/runtime/dex/code_item_accessors.h
@@ -131,20 +131,16 @@
  public:
   CodeItemDebugInfoAccessor() = default;
 
-  // Handles null code items, but not null dex files.
-  ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
-                                          const DexFile::CodeItem* code_item);
-
   // Initialize with an existing offset.
   ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
                                           const DexFile::CodeItem* code_item,
-                                          uint32_t debug_info_offset) {
-    Init(dex_file, code_item, debug_info_offset);
+                                          uint32_t dex_method_index) {
+    Init(dex_file, code_item, dex_method_index);
   }
 
   ALWAYS_INLINE void Init(const DexFile& dex_file,
                           const DexFile::CodeItem* code_item,
-                          uint32_t debug_info_offset);
+                          uint32_t dex_method_index);
 
   ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
 
@@ -159,7 +155,7 @@
                             void* context) const;
 
  protected:
-  ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item, uint32_t dex_method_index);
   ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
 
  private:
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index b29d10b..2e21956 100644
--- a/runtime/dex/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -19,6 +19,7 @@
 #include <memory>
 
 #include "common_runtime_test.h"
+#include "art_dex_file_loader.h"
 #include "dex_file_loader.h"
 #include "mem_map.h"
 
@@ -44,13 +45,13 @@
     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));
+  const ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const DexFile> dex(dex_file_loader.Open("location",
+                                                          /*location_checksum*/ 123,
+                                                          std::move(map),
+                                                          /*verify*/false,
+                                                          /*verify_checksum*/false,
+                                                          &error_msg));
   CHECK(dex != nullptr) << error_msg;
   return dex;
 }
diff --git a/runtime/dex/compact_dex_debug_info.cc b/runtime/dex/compact_dex_debug_info.cc
new file mode 100644
index 0000000..19495ca
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 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 "compact_dex_debug_info.h"
+
+#include "compact_dex_utils.h"
+#include "leb128.h"
+
+namespace art {
+
+constexpr size_t CompactDexDebugInfoOffsetTable::kElementsPerIndex;
+
+CompactDexDebugInfoOffsetTable::Accessor::Accessor(const uint8_t* data_begin,
+                                                   uint32_t debug_info_base,
+                                                   uint32_t debug_info_table_offset)
+    : table_(reinterpret_cast<const uint32_t*>(data_begin + debug_info_table_offset)),
+      debug_info_base_(debug_info_base),
+      data_begin_(data_begin) {}
+
+uint32_t CompactDexDebugInfoOffsetTable::Accessor::GetDebugInfoOffset(uint32_t method_idx) const {
+  const uint32_t offset = table_[method_idx / kElementsPerIndex];
+  const size_t bit_index = method_idx % kElementsPerIndex;
+
+  const uint8_t* block = data_begin_ + offset;
+  uint16_t bit_mask = *block;
+  ++block;
+  bit_mask = (bit_mask << kBitsPerByte) | *block;
+  ++block;
+  if ((bit_mask & (1 << bit_index)) == 0) {
+    // Bit is not set means the offset is 0 for the debug info.
+    return 0u;
+  }
+  // Trim off the bits above the index we want and count how many bits are set. This is how many
+  // lebs we need to decode.
+  size_t count = POPCOUNT(static_cast<uintptr_t>(bit_mask) << (kBitsPerIntPtrT - 1 - bit_index));
+  DCHECK_GT(count, 0u);
+  uint32_t current_offset = debug_info_base_;
+  do {
+    current_offset += DecodeUnsignedLeb128(&block);
+    --count;
+  } while (count > 0);
+  return current_offset;
+}
+
+void CompactDexDebugInfoOffsetTable::Build(const std::vector<uint32_t>& debug_info_offsets,
+                                           std::vector<uint8_t>* out_data,
+                                           uint32_t* out_min_offset,
+                                           uint32_t* out_table_offset) {
+  DCHECK(out_data != nullptr);
+  DCHECK(out_data->empty());
+  // Calculate the base offset and return it.
+  *out_min_offset = std::numeric_limits<uint32_t>::max();
+  for (const uint32_t offset : debug_info_offsets) {
+    if (offset != 0u) {
+      *out_min_offset = std::min(*out_min_offset, offset);
+    }
+  }
+  // Write the leb blocks and store the important offsets (each kElementsPerIndex elements).
+  size_t block_start = 0;
+
+  std::vector<uint32_t> offset_table;
+
+  // Write data first then the table.
+  while (block_start < debug_info_offsets.size()) {
+    // Write the offset of the block for each block.
+    offset_table.push_back(out_data->size());
+
+    // Block size of up to kElementsPerIndex
+    const size_t block_size = std::min(debug_info_offsets.size() - block_start, kElementsPerIndex);
+
+    // Calculate bit mask since need to write that first.
+    uint16_t bit_mask = 0u;
+    for (size_t i = 0; i < block_size; ++i) {
+      if (debug_info_offsets[block_start + i] != 0u) {
+        bit_mask |= 1 << i;
+      }
+    }
+    // Write bit mask.
+    out_data->push_back(static_cast<uint8_t>(bit_mask >> kBitsPerByte));
+    out_data->push_back(static_cast<uint8_t>(bit_mask));
+
+    // Write debug info offsets relative to the current offset.
+    uint32_t current_offset = *out_min_offset;
+    for (size_t i = 0; i < block_size; ++i) {
+      const uint32_t debug_info_offset = debug_info_offsets[block_start + i];
+      if (debug_info_offset != 0u) {
+        uint32_t delta = debug_info_offset - current_offset;
+        EncodeUnsignedLeb128(out_data, delta);
+        current_offset = debug_info_offset;
+      }
+    }
+
+    block_start += block_size;
+  }
+
+  // Write the offset table.
+  AlignmentPadVector(out_data, alignof(uint32_t));
+  *out_table_offset = out_data->size();
+  out_data->insert(out_data->end(),
+                   reinterpret_cast<const uint8_t*>(&offset_table[0]),
+                   reinterpret_cast<const uint8_t*>(&offset_table[0] + offset_table.size()));
+}
+
+}  // namespace art
diff --git a/runtime/dex/compact_dex_debug_info.h b/runtime/dex/compact_dex_debug_info.h
new file mode 100644
index 0000000..1aff758
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 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_DEX_COMPACT_DEX_DEBUG_INFO_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
+
+#include <cstdint>
+#include <vector>
+
+namespace art {
+
+// Debug offset table for compact dex, aims to minimize size while still providing reasonable
+// speed (10-20ns average time per lookup on host).
+class CompactDexDebugInfoOffsetTable {
+ public:
+  // This value is coupled with the leb chunk bitmask. That logic must also be adjusted when the
+  // integer is modified.
+  static constexpr size_t kElementsPerIndex = 16;
+
+  // Leb block format:
+  // [uint16_t] 16 bit mask for what method ids actually have a debug info offset for the chunk.
+  // [lebs] Up to 16 lebs encoded using leb128, one leb bit. The leb specifies how the offset
+  // changes compared to the previous index.
+
+  class Accessor {
+   public:
+    Accessor(const uint8_t* data_begin,
+             uint32_t debug_info_base,
+             uint32_t debug_info_table_offset);
+
+    // Return the debug info for a method index (or 0 if it doesn't have one).
+    uint32_t GetDebugInfoOffset(uint32_t method_idx) const;
+
+   private:
+    const uint32_t* const table_;
+    const uint32_t debug_info_base_;
+    const uint8_t* const data_begin_;
+  };
+
+  // Returned offsets are all relative to debug_info_offsets.
+  static void Build(const std::vector<uint32_t>& debug_info_offsets,
+                    std::vector<uint8_t>* out_data,
+                    uint32_t* out_min_offset,
+                    uint32_t* out_table_offset);
+
+  // 32 bit aligned for the offset table.
+  static constexpr size_t kAlignment = sizeof(uint32_t);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
diff --git a/runtime/dex/compact_dex_debug_info_test.cc b/runtime/dex/compact_dex_debug_info_test.cc
new file mode 100644
index 0000000..02b95e6
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info_test.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 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 <vector>
+#include <sys/mman.h>
+
+#include "base/logging.h"
+#include "dex/compact_dex_debug_info.h"
+#include "gtest/gtest.h"
+#include "mem_map.h"
+
+namespace art {
+
+TEST(CompactDexDebugInfoTest, TestBuildAndAccess) {
+  MemMap::Init();
+
+  const size_t kDebugInfoMinOffset = 1234567;
+  std::vector<uint32_t> offsets = {
+      0, 17, 2, 3, 11, 0, 0, 0, 0, 1, 0, 1552, 100, 122, 44, 1234567, 0, 0,
+      std::numeric_limits<uint32_t>::max() - kDebugInfoMinOffset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,
+  };
+  // Add some large offset since the debug info section will never be that close to the beginning
+  // of the file.
+  for (uint32_t& offset : offsets) {
+    if (offset != 0u) {
+      offset += kDebugInfoMinOffset;
+    }
+  }
+
+  std::vector<uint8_t> data;
+  uint32_t base_offset = 0;
+  uint32_t table_offset = 0;
+  CompactDexDebugInfoOffsetTable::Build(offsets,
+                                        /*out*/ &data,
+                                        /*out*/ &base_offset,
+                                        /*out*/ &table_offset);
+  EXPECT_GE(base_offset, kDebugInfoMinOffset);
+  EXPECT_LT(table_offset, data.size());
+  ASSERT_GT(data.size(), 0u);
+  const size_t before_size = offsets.size() * sizeof(offsets.front());
+  EXPECT_LT(data.size(), before_size);
+
+  // Note that the accessor requires the data to be aligned. Use memmap to accomplish this.
+  std::string error_msg;
+  // Leave some extra room since we don't copy the table at the start (for testing).
+  constexpr size_t kExtraOffset = 4 * 128;
+  std::unique_ptr<MemMap> fake_dex(MemMap::MapAnonymous("fake dex",
+                                                        nullptr,
+                                                        data.size() + kExtraOffset,
+                                                        PROT_READ | PROT_WRITE,
+                                                        /*low_4gb*/ false,
+                                                        /*reuse*/ false,
+                                                        &error_msg));
+  ASSERT_TRUE(fake_dex != nullptr) << error_msg;
+  std::copy(data.begin(), data.end(), fake_dex->Begin() + kExtraOffset);
+
+  CompactDexDebugInfoOffsetTable::Accessor accessor(fake_dex->Begin() + kExtraOffset,
+                                                    base_offset,
+                                                    table_offset);
+  for (size_t i = 0; i < offsets.size(); ++i) {
+    EXPECT_EQ(offsets[i], accessor.GetDebugInfoOffset(i));
+  }
+
+  // Sort to produce a try and produce a smaller table. This happens because the leb diff is smaller
+  // for sorted increasing order.
+  std::sort(offsets.begin(), offsets.end());
+  std::vector<uint8_t> sorted_data;
+  CompactDexDebugInfoOffsetTable::Build(offsets,
+                                        /*out*/ &sorted_data,
+                                        /*out*/ &base_offset,
+                                        /*out*/ &table_offset);
+  EXPECT_LT(sorted_data.size(), data.size());
+  {
+    ScopedLogSeverity sls(LogSeverity::INFO);
+    LOG(INFO) << "raw size " << before_size
+              << " table size " << data.size()
+              << " sorted table size " << sorted_data.size();
+  }
+}
+
+}  // namespace art
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
index 2d1ee04..ff193ff 100644
--- a/runtime/dex/compact_dex_file.cc
+++ b/runtime/dex/compact_dex_file.cc
@@ -63,4 +63,21 @@
       reinterpret_cast<uintptr_t>(&item);
 }
 
+CompactDexFile::CompactDexFile(const uint8_t* base,
+                               size_t size,
+                               const std::string& location,
+                               uint32_t location_checksum,
+                               const OatDexFile* oat_dex_file,
+                               DexFileContainer* container)
+    : DexFile(base,
+              size,
+              location,
+              location_checksum,
+              oat_dex_file,
+              container,
+              /*is_compact_dex*/ true),
+      debug_info_offsets_(Begin() + GetHeader().debug_info_offsets_pos_,
+                          GetHeader().debug_info_base_,
+                          GetHeader().debug_info_offsets_table_offset_) {}
+
 }  // namespace art
diff --git a/runtime/dex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
index 280c6f7..af782a9 100644
--- a/runtime/dex/compact_dex_file.h
+++ b/runtime/dex/compact_dex_file.h
@@ -19,6 +19,7 @@
 
 #include "base/casts.h"
 #include "dex_file.h"
+#include "dex/compact_dex_debug_info.h"
 
 namespace art {
 
@@ -41,13 +42,45 @@
    private:
     uint32_t feature_flags_ = 0u;
 
+    // Position in the compact dex file for the debug info table data starts.
+    uint32_t debug_info_offsets_pos_ = 0u;
+
+    // Offset into the debug info table data where the lookup table is.
+    uint32_t debug_info_offsets_table_offset_ = 0u;
+
+    // Base offset of where debug info starts in the dex file.
+    uint32_t debug_info_base_ = 0u;
+
+    friend class CompactDexFile;
     friend class CompactDexWriter;
   };
 
+  // Like the standard code item except without a debug info offset.
   struct CodeItem : public DexFile::CodeItem {
+    static constexpr size_t kAlignment = sizeof(uint32_t);
+
    private:
-    // TODO: Insert compact dex specific fields here.
+    CodeItem() = default;
+
+    uint16_t registers_size_;            // the number of registers used by this code
+                                         //   (locals + parameters)
+    uint16_t ins_size_;                  // the number of words of incoming arguments to the method
+                                         //   that this code is for
+    uint16_t outs_size_;                 // the number of words of outgoing argument space required
+                                         //   by this code for method invocation
+    uint16_t tries_size_;                // the number of try_items for this instance. If non-zero,
+                                         //   then these appear as the tries array just after the
+                                         //   insns in this instance.
+
+    uint32_t insns_size_in_code_units_;  // size of the insns array, in 2 byte code units
+    uint16_t insns_[1];                  // actual array of bytecode.
+
+    ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+    friend class CodeItemDataAccessor;
+    friend class CodeItemDebugInfoAccessor;
+    friend class CodeItemInstructionAccessor;
     friend class CompactDexFile;
+    friend class CompactDexWriter;
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
   };
 
@@ -73,25 +106,22 @@
 
   uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
 
+  uint32_t GetDebugInfoOffset(uint32_t dex_method_index) const {
+    return debug_info_offsets_.GetDebugInfoOffset(dex_method_index);
+  }
+
  private:
-  // Not supported yet.
   CompactDexFile(const uint8_t* base,
                  size_t size,
                  const std::string& location,
                  uint32_t location_checksum,
                  const OatDexFile* oat_dex_file,
-                 DexFileContainer* container)
-      : DexFile(base,
-                size,
-                location,
-                location_checksum,
-                oat_dex_file,
-                container,
-                /*is_compact_dex*/ true) {}
+                 DexFileContainer* container);
+
+  CompactDexDebugInfoOffsetTable::Accessor debug_info_offsets_;
 
   friend class DexFile;
   friend class DexFileLoader;
-
   DISALLOW_COPY_AND_ASSIGN(CompactDexFile);
 };
 
diff --git a/runtime/dex/compact_dex_utils.h b/runtime/dex/compact_dex_utils.h
new file mode 100644
index 0000000..1c7e951
--- /dev/null
+++ b/runtime/dex/compact_dex_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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_DEX_COMPACT_DEX_UTILS_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
+
+#include <vector>
+
+#include "base/bit_utils.h"
+
+namespace art {
+
+// Add padding to the end of the array until the size is aligned.
+template <typename T, template<typename> class Allocator>
+static inline void AlignmentPadVector(std::vector<T, Allocator<T>>* dest,
+                                      size_t alignment) {
+  while (!IsAlignedParam(dest->size(), alignment)) {
+    dest->push_back(T());
+  }
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h
index c2a36ce..183d84e 100644
--- a/runtime/dex/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -301,43 +301,12 @@
     DISALLOW_COPY_AND_ASSIGN(CallSiteIdItem);
   };
 
-  // Raw code_item.
+  // Base code_item, compact dex and standard dex have different code item layouts.
   struct CodeItem {
-    // Used when quickening / unquickening.
-    void SetDebugInfoOffset(uint32_t new_offset) {
-      debug_info_off_ = new_offset;
-    }
-
-    uint32_t GetDebugInfoOffset() const {
-      return debug_info_off_;
-    }
-
    protected:
-    uint16_t registers_size_;            // the number of registers used by this code
-                                         //   (locals + parameters)
-    uint16_t ins_size_;                  // the number of words of incoming arguments to the method
-                                         //   that this code is for
-    uint16_t outs_size_;                 // the number of words of outgoing argument space required
-                                         //   by this code for method invocation
-    uint16_t tries_size_;                // the number of try_items for this instance. If non-zero,
-                                         //   then these appear as the tries array just after the
-                                         //   insns in this instance.
-    // Normally holds file offset to debug info stream. In case the method has been quickened
-    // holds an offset in the Vdex file containing both the actual debug_info_off and the
-    // quickening info offset.
-    // Don't use this field directly, use OatFile::GetDebugInfoOffset in general ART code,
-    // or DexFile::GetDebugInfoOffset in code that are not using a Runtime.
-    uint32_t debug_info_off_;
-
-    uint32_t insns_size_in_code_units_;  // size of the insns array, in 2 byte code units
-    uint16_t insns_[1];                  // actual array of bytecode.
+    CodeItem() = default;
 
    private:
-    ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
-    friend class CodeItemDataAccessor;
-    friend class CodeItemDebugInfoAccessor;
-    friend class CodeItemInstructionAccessor;
-    friend class VdexFile;  // TODO: Remove this one when it's cleaned up.
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
   };
 
@@ -348,6 +317,8 @@
     uint16_t handler_off_;
 
    private:
+    TryItem() = default;
+    friend class DexWriter;
     DISALLOW_COPY_AND_ASSIGN(TryItem);
   };
 
@@ -712,15 +683,6 @@
     return reinterpret_cast<const CodeItem*>(addr);
   }
 
-  uint32_t GetDebugInfoOffset(const CodeItem* code_item) const {
-    if (code_item == nullptr) {
-      return 0;
-    }
-    CHECK(oat_dex_file_ == nullptr)
-        << "Should only use GetDebugInfoOffset in a non runtime setup";
-    return code_item->GetDebugInfoOffset();
-  }
-
   const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const;
 
   // Returns the number of prototype identifiers in the .dex file.
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index fafd698..10aef56 100644
--- a/runtime/dex/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -16,72 +16,25 @@
 
 #include "dex_file_loader.h"
 
-#include <sys/mman.h>  // For the PROT_* and MAP_* constants.
-#include <sys/stat.h>
+// #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
+// #include <sys/stat.h>
 
 #include "android-base/stringprintf.h"
 
 #include "base/file_magic.h"
 #include "base/stl_util.h"
-#include "base/systrace.h"
-#include "base/unix_file/fd_file.h"
+// #include "base/systrace.h"
+// #include "base/unix_file/fd_file.h"
 #include "compact_dex_file.h"
 #include "dex_file.h"
 #include "dex_file_verifier.h"
 #include "standard_dex_file.h"
-#include "zip_archive.h"
+// #include "zip_archive.h"
 
 namespace art {
 
-namespace {
-
-class MemMapContainer : public DexFileContainer {
- public:
-  explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { }
-  virtual ~MemMapContainer() OVERRIDE { }
-
-  int GetPermissions() OVERRIDE {
-    if (mem_map_.get() == nullptr) {
-      return 0;
-    } else {
-      return mem_map_->GetProtect();
-    }
-  }
-
-  bool IsReadOnly() OVERRIDE {
-    return GetPermissions() == PROT_READ;
-  }
-
-  bool EnableWrite() OVERRIDE {
-    CHECK(IsReadOnly());
-    if (mem_map_.get() == nullptr) {
-      return false;
-    } else {
-      return mem_map_->Protect(PROT_READ | PROT_WRITE);
-    }
-  }
-
-  bool DisableWrite() OVERRIDE {
-    CHECK(!IsReadOnly());
-    if (mem_map_.get() == nullptr) {
-      return false;
-    } else {
-      return mem_map_->Protect(PROT_READ);
-    }
-  }
-
- private:
-  std::unique_ptr<MemMap> mem_map_;
-  DISALLOW_COPY_AND_ASSIGN(MemMapContainer);
-};
-
-}  // namespace
-
 using android::base::StringPrintf;
 
-static constexpr OatDexFile* kNoOatDexFile = nullptr;
-
-
 bool DexFileLoader::IsMagicValid(uint32_t magic) {
   return IsMagicValid(reinterpret_cast<uint8_t*>(&magic));
 }
@@ -101,63 +54,6 @@
   return false;
 }
 
-bool DexFileLoader::GetMultiDexChecksums(const char* filename,
-                                         std::vector<uint32_t>* checksums,
-                                         std::string* error_msg,
-                                         int zip_fd) {
-  CHECK(checksums != nullptr);
-  uint32_t magic;
-
-  File fd;
-  if (zip_fd != -1) {
-     if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
-       fd = File(zip_fd, false /* check_usage */);
-     }
-  } else {
-    fd = OpenAndReadMagic(filename, &magic, error_msg);
-  }
-  if (fd.Fd() == -1) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  if (IsZipMagic(magic)) {
-    std::unique_ptr<ZipArchive> zip_archive(
-        ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
-    if (zip_archive.get() == nullptr) {
-      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
-                                error_msg->c_str());
-      return false;
-    }
-
-    uint32_t i = 0;
-    std::string zip_entry_name = GetMultiDexClassesDexName(i++);
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
-    if (zip_entry.get() == nullptr) {
-      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
-          zip_entry_name.c_str(), error_msg->c_str());
-      return false;
-    }
-
-    do {
-      checksums->push_back(zip_entry->GetCrc32());
-      zip_entry_name = GetMultiDexClassesDexName(i++);
-      zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
-    } while (zip_entry.get() != nullptr);
-    return true;
-  }
-  if (IsMagicValid(magic)) {
-    std::unique_ptr<const DexFile> dex_file(
-        OpenFile(fd.Release(), filename, false, false, error_msg));
-    if (dex_file == nullptr) {
-      return false;
-    }
-    checksums->push_back(dex_file->GetHeader().checksum_);
-    return true;
-  }
-  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
-  return false;
-}
-
 bool DexFileLoader::IsMultiDexLocation(const char* location) {
   return strrchr(location, kMultiDexSeparator) != nullptr;
 }
@@ -187,326 +83,102 @@
   }
 }
 
-std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
-                                                   size_t size,
-                                                   const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   const OatDexFile* oat_dex_file,
-                                                   bool verify,
-                                                   bool verify_checksum,
-                                                   std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file from RAM ") + location);
-  return OpenCommon(base,
-                    size,
-                    location,
-                    location_checksum,
-                    oat_dex_file,
-                    verify,
-                    verify_checksum,
-                    error_msg,
-                    /*container*/ nullptr,
-                    /*verify_result*/ nullptr);
-}
+// All of the implementations here should be independent of the runtime.
+// TODO: implement all the virtual methods.
 
-std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> map,
-                                                   bool verify,
-                                                   bool verify_checksum,
-                                                   std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
-  CHECK(map.get() != nullptr);
-
-  if (map->Size() < sizeof(DexFile::Header)) {
-    *error_msg = StringPrintf(
-        "DexFile: failed to open dex file '%s' that is too short to have a header",
-        location.c_str());
-    return nullptr;
-  }
-
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 location_checksum,
-                                                 kNoOatDexFile,
-                                                 verify,
-                                                 verify_checksum,
-                                                 error_msg,
-                                                 new MemMapContainer(std::move(map)),
-                                                 /*verify_result*/ nullptr);
-  return dex_file;
-}
-
-bool DexFileLoader::Open(const char* filename,
-                         const std::string& location,
-                         bool verify,
-                         bool verify_checksum,
-                         std::string* error_msg,
-                         std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
-  uint32_t magic;
-  File fd = OpenAndReadMagic(filename, &magic, error_msg);
-  if (fd.Fd() == -1) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  if (IsZipMagic(magic)) {
-    return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
-  }
-  if (IsMagicValid(magic)) {
-    std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
-                                                     location,
-                                                     verify,
-                                                     verify_checksum,
-                                                     error_msg));
-    if (dex_file.get() != nullptr) {
-      dex_files->push_back(std::move(dex_file));
-      return true;
-    } else {
-      return false;
-    }
-  }
-  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+bool DexFileLoader::GetMultiDexChecksums(const char* filename ATTRIBUTE_UNUSED,
+                                         std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED,
+                                         std::string* error_msg,
+                                         int zip_fd ATTRIBUTE_UNUSED) const {
+  *error_msg = "UNIMPLEMENTED";
   return false;
 }
 
-std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd,
-                                                      const std::string& location,
-                                                      bool verify,
-                                                      bool verify_checksum,
-                                                      std::string* error_msg) {
-  ScopedTrace trace("Open dex file " + std::string(location));
-  return OpenFile(fd, location, verify, verify_checksum, error_msg);
+std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base ATTRIBUTE_UNUSED,
+                                                   size_t size ATTRIBUTE_UNUSED,
+                                                   const std::string& location ATTRIBUTE_UNUSED,
+                                                   uint32_t location_checksum ATTRIBUTE_UNUSED,
+                                                   const OatDexFile* oat_dex_file ATTRIBUTE_UNUSED,
+                                                   bool verify ATTRIBUTE_UNUSED,
+                                                   bool verify_checksum ATTRIBUTE_UNUSED,
+                                                   std::string* error_msg) const {
+  *error_msg = "UNIMPLEMENTED";
+  return nullptr;
 }
 
-bool DexFileLoader::OpenZip(int fd,
-                            const std::string& location,
-                            bool verify,
-                            bool verify_checksum,
-                            std::string* error_msg,
-                            std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace("Dex file open Zip " + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
-  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
-  if (zip_archive.get() == nullptr) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  return OpenAllDexFilesFromZip(
-      *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
+std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location ATTRIBUTE_UNUSED,
+                                                   uint32_t location_checksum ATTRIBUTE_UNUSED,
+                                                   std::unique_ptr<MemMap> map ATTRIBUTE_UNUSED,
+                                                   bool verify ATTRIBUTE_UNUSED,
+                                                   bool verify_checksum ATTRIBUTE_UNUSED,
+                                                   std::string* error_msg) const {
+  *error_msg = "UNIMPLEMENTED";
+  return nullptr;
 }
 
-std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd,
-                                                       const std::string& location,
-                                                       bool verify,
-                                                       bool verify_checksum,
-                                                       std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
-  CHECK(!location.empty());
-  std::unique_ptr<MemMap> map;
-  {
-    File delayed_close(fd, /* check_usage */ false);
-    struct stat sbuf;
-    memset(&sbuf, 0, sizeof(sbuf));
-    if (fstat(fd, &sbuf) == -1) {
-      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
-                                strerror(errno));
-      return nullptr;
-    }
-    if (S_ISDIR(sbuf.st_mode)) {
-      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
-      return nullptr;
-    }
-    size_t length = sbuf.st_size;
-    map.reset(MemMap::MapFile(length,
-                              PROT_READ,
-                              MAP_PRIVATE,
-                              fd,
-                              0,
-                              /*low_4gb*/false,
-                              location.c_str(),
-                              error_msg));
-    if (map == nullptr) {
-      DCHECK(!error_msg->empty());
-      return nullptr;
-    }
-  }
+bool DexFileLoader::Open(
+    const char* filename ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
+    std::string* error_msg,
+    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+  *error_msg = "UNIMPLEMENTED";
+  return false;
+}
 
-  if (map->Size() < sizeof(DexFile::Header)) {
-    *error_msg = StringPrintf(
-        "DexFile: failed to open dex file '%s' that is too short to have a header",
-        location.c_str());
-    return nullptr;
-  }
+std::unique_ptr<const DexFile> DexFileLoader::OpenDex(
+    int fd ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
+    std::string* error_msg) const {
+  *error_msg = "UNIMPLEMENTED";
+  return nullptr;
+}
 
-  const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
+bool DexFileLoader::OpenZip(
+    int fd ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
+    std::string* error_msg,
+    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+  *error_msg = "UNIMPLEMENTED";
+  return false;
+}
 
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 dex_header->checksum_,
-                                                 kNoOatDexFile,
-                                                 verify,
-                                                 verify_checksum,
-                                                 error_msg,
-                                                 new MemMapContainer(std::move(map)),
-                                                 /*verify_result*/ nullptr);
-
-  return dex_file;
+std::unique_ptr<const DexFile> DexFileLoader::OpenFile(
+    int fd ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
+    std::string* error_msg) const {
+  *error_msg = "UNIMPLEMENTED";
+  return nullptr;
 }
 
 std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
-    const ZipArchive& zip_archive,
-    const char* entry_name,
-    const std::string& location,
-    bool verify,
-    bool verify_checksum,
+    const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
+    const char* entry_name ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
     std::string* error_msg,
-    ZipOpenErrorCode* error_code) {
-  ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
-  CHECK(!location.empty());
-  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
-  if (zip_entry == nullptr) {
-    *error_code = ZipOpenErrorCode::kEntryNotFound;
-    return nullptr;
-  }
-  if (zip_entry->GetUncompressedLength() == 0) {
-    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
-    *error_code = ZipOpenErrorCode::kDexFileError;
-    return nullptr;
-  }
-
-  std::unique_ptr<MemMap> map;
-  if (zip_entry->IsUncompressed()) {
-    if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
-      // Do not mmap unaligned ZIP entries because
-      // doing so would fail dex verification which requires 4 byte alignment.
-      LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
-                   << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
-                   << "Falling back to extracting file.";
-    } else {
-      // Map uncompressed files within zip as file-backed to avoid a dirty copy.
-      map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
-      if (map == nullptr) {
-        LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
-                     << "is your ZIP file corrupted? Falling back to extraction.";
-        // Try again with Extraction which still has a chance of recovery.
-      }
-    }
-  }
-
-  if (map == nullptr) {
-    // Default path for compressed ZIP entries,
-    // and fallback for stored ZIP entries.
-    map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
-  }
-
-  if (map == nullptr) {
-    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
-                              error_msg->c_str());
-    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
-    return nullptr;
-  }
-  VerifyResult verify_result;
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 zip_entry->GetCrc32(),
-                                                 kNoOatDexFile,
-                                                 verify,
-                                                 verify_checksum,
-                                                 error_msg,
-                                                 new MemMapContainer(std::move(map)),
-                                                 &verify_result);
-  if (dex_file == nullptr) {
-    if (verify_result == VerifyResult::kVerifyNotAttempted) {
-      *error_code = ZipOpenErrorCode::kDexFileError;
-    } else {
-      *error_code = ZipOpenErrorCode::kVerifyError;
-    }
-    return nullptr;
-  }
-  if (!dex_file->DisableWrite()) {
-    *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
-    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
-    return nullptr;
-  }
-  CHECK(dex_file->IsReadOnly()) << location;
-  if (verify_result != VerifyResult::kVerifySucceeded) {
-    *error_code = ZipOpenErrorCode::kVerifyError;
-    return nullptr;
-  }
-  *error_code = ZipOpenErrorCode::kNoError;
-  return dex_file;
+    ZipOpenErrorCode* error_code ATTRIBUTE_UNUSED) const {
+  *error_msg = "UNIMPLEMENTED";
+  return nullptr;
 }
 
-// Technically we do not have a limitation with respect to the number of dex files that can be in a
-// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
-// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
-// seems an excessive number.
-static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
-
-bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
-                                           const std::string& location,
-                                           bool verify,
-                                           bool verify_checksum,
-                                           std::string* error_msg,
-                                           std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace("Dex file open from Zip " + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
-  ZipOpenErrorCode error_code;
-  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
-                                                                kClassesDex,
-                                                                location,
-                                                                verify,
-                                                                verify_checksum,
-                                                                error_msg,
-                                                                &error_code));
-  if (dex_file.get() == nullptr) {
-    return false;
-  } else {
-    // Had at least classes.dex.
-    dex_files->push_back(std::move(dex_file));
-
-    // Now try some more.
-
-    // We could try to avoid std::string allocations by working on a char array directly. As we
-    // do not expect a lot of iterations, this seems too involved and brittle.
-
-    for (size_t i = 1; ; ++i) {
-      std::string name = GetMultiDexClassesDexName(i);
-      std::string fake_location = GetMultiDexLocation(i, location.c_str());
-      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
-                                                                         name.c_str(),
-                                                                         fake_location,
-                                                                         verify,
-                                                                         verify_checksum,
-                                                                         error_msg,
-                                                                         &error_code));
-      if (next_dex_file.get() == nullptr) {
-        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
-          LOG(WARNING) << "Zip open failed: " << *error_msg;
-        }
-        break;
-      } else {
-        dex_files->push_back(std::move(next_dex_file));
-      }
-
-      if (i == kWarnOnManyDexFilesThreshold) {
-        LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
-                     << " dex files. Please consider coalescing and shrinking the number to "
-                        " avoid runtime overhead.";
-      }
-
-      if (i == std::numeric_limits<size_t>::max()) {
-        LOG(ERROR) << "Overflow in number of dex files!";
-        break;
-      }
-    }
-
-    return true;
-  }
+bool DexFileLoader::OpenAllDexFilesFromZip(
+    const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
+    const std::string& location ATTRIBUTE_UNUSED,
+    bool verify ATTRIBUTE_UNUSED,
+    bool verify_checksum ATTRIBUTE_UNUSED,
+    std::string* error_msg,
+    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+  *error_msg = "UNIMPLEMENTED";
+  return false;
 }
 
 std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h
index 7db8d8e..6f1afd6 100644
--- a/runtime/dex/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -46,6 +46,8 @@
   // Return true if the corresponding version and magic is valid.
   static bool IsVersionAndMagicValid(const uint8_t* magic);
 
+  virtual ~DexFileLoader() { }
+
   // Returns the checksums of a file for comparison with GetLocationChecksum().
   // For .dex files, this is the single header checksum.
   // For zip files, this is the zip entry CRC32 checksum for classes.dex and
@@ -55,55 +57,55 @@
   // zip_fd is -1, the method will try to open the `filename` and read the
   // content from it.
   // Return true if the checksums could be found, false otherwise.
-  static bool GetMultiDexChecksums(const char* filename,
-                                   std::vector<uint32_t>* checksums,
-                                   std::string* error_msg,
-                                   int zip_fd = -1);
+  virtual bool GetMultiDexChecksums(const char* filename,
+                                    std::vector<uint32_t>* checksums,
+                                    std::string* error_msg,
+                                    int zip_fd = -1) const;
 
   // Check whether a location denotes a multidex dex file. This is a very simple check: returns
   // whether the string contains the separator character.
   static bool IsMultiDexLocation(const char* location);
 
   // Opens .dex file, backed by existing memory
-  static std::unique_ptr<const DexFile> Open(const uint8_t* base,
-                                             size_t size,
-                                             const std::string& location,
-                                             uint32_t location_checksum,
-                                             const OatDexFile* oat_dex_file,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg);
+  virtual std::unique_ptr<const DexFile> Open(const uint8_t* base,
+                                              size_t size,
+                                              const std::string& location,
+                                              uint32_t location_checksum,
+                                              const OatDexFile* oat_dex_file,
+                                              bool verify,
+                                              bool verify_checksum,
+                                              std::string* error_msg) const;
 
   // Opens .dex file that has been memory-mapped by the caller.
-  static std::unique_ptr<const DexFile> Open(const std::string& location,
-                                             uint32_t location_checkum,
-                                             std::unique_ptr<MemMap> mem_map,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg);
+  virtual std::unique_ptr<const DexFile> Open(const std::string& location,
+                                              uint32_t location_checkum,
+                                              std::unique_ptr<MemMap> mem_map,
+                                              bool verify,
+                                              bool verify_checksum,
+                                              std::string* error_msg) const;
 
   // Opens all .dex files found in the file, guessing the container format based on file extension.
-  static bool Open(const char* filename,
-                   const std::string& location,
-                   bool verify,
-                   bool verify_checksum,
-                   std::string* error_msg,
-                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
+  virtual bool Open(const char* filename,
+                    const std::string& location,
+                    bool verify,
+                    bool verify_checksum,
+                    std::string* error_msg,
+                    std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
   // Open a single dex file from an fd. This function closes the fd.
-  static std::unique_ptr<const DexFile> OpenDex(int fd,
-                                                const std::string& location,
-                                                bool verify,
-                                                bool verify_checksum,
-                                                std::string* error_msg);
+  virtual std::unique_ptr<const DexFile> OpenDex(int fd,
+                                                 const std::string& location,
+                                                 bool verify,
+                                                 bool verify_checksum,
+                                                 std::string* error_msg) const;
 
   // Opens dex files from within a .jar, .zip, or .apk file
-  static bool OpenZip(int fd,
-                      const std::string& location,
-                      bool verify,
-                      bool verify_checksum,
-                      std::string* error_msg,
-                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
+  virtual bool OpenZip(int fd,
+                       const std::string& location,
+                       bool verify,
+                       bool verify_checksum,
+                       std::string* error_msg,
+                       std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
   // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
   // index == 0, and classes{index + 1}.dex else.
@@ -148,13 +150,7 @@
     return (pos == std::string::npos) ? std::string() : location.substr(pos);
   }
 
- private:
-  static std::unique_ptr<const DexFile> OpenFile(int fd,
-                                                 const std::string& location,
-                                                 bool verify,
-                                                 bool verify_checksum,
-                                                 std::string* error_msg);
-
+ protected:
   enum class ZipOpenErrorCode {
     kNoError,
     kEntryNotFound,
@@ -164,24 +160,6 @@
     kVerifyError
   };
 
-  // Open all classesXXX.dex files from a zip archive.
-  static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
-                                     const std::string& location,
-                                     bool verify,
-                                     bool verify_checksum,
-                                     std::string* error_msg,
-                                     std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
-  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
-  // return.
-  static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
-                                                              const char* entry_name,
-                                                              const std::string& location,
-                                                              bool verify,
-                                                              bool verify_checksum,
-                                                              std::string* error_msg,
-                                                              ZipOpenErrorCode* error_code);
-
   enum class VerifyResult {  // private
     kVerifyNotAttempted,
     kVerifySucceeded,
@@ -198,6 +176,31 @@
                                              std::string* error_msg,
                                              DexFileContainer* container,
                                              VerifyResult* verify_result);
+
+ private:
+  virtual std::unique_ptr<const DexFile> OpenFile(int fd,
+                                                  const std::string& location,
+                                                  bool verify,
+                                                  bool verify_checksum,
+                                                  std::string* error_msg) const;
+
+  // Open all classesXXX.dex files from a zip archive.
+  virtual bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                                      const std::string& location,
+                                      bool verify,
+                                      bool verify_checksum,
+                                      std::string* error_msg,
+                                      std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
+
+  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+  // return.
+  virtual std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+                                                               const char* entry_name,
+                                                               const std::string& location,
+                                                               bool verify,
+                                                               bool verify_checksum,
+                                                               std::string* error_msg,
+                                                               ZipOpenErrorCode* error_code) const;
 };
 
 }  // namespace art
diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc
index 3ee115c..cb721af 100644
--- a/runtime/dex/dex_file_test.cc
+++ b/runtime/dex/dex_file_test.cc
@@ -20,6 +20,7 @@
 
 #include <memory>
 
+#include "art_dex_file_loader.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "code_item_accessors-inl.h"
@@ -237,7 +238,8 @@
   ScopedObjectAccess soa(Thread::Current());
   static constexpr bool kVerifyChecksum = true;
   std::vector<std::unique_ptr<const DexFile>> tmp;
-  bool success = DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  bool success = dex_file_loader.Open(
       location, location, /* verify */ true, kVerifyChecksum, error_msg, &tmp);
   if (success) {
     for (std::unique_ptr<const DexFile>& dex_file : tmp) {
@@ -277,12 +279,13 @@
                                                       /* reuse */ false,
                                                       &error_message));
   memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
-  std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
-                                                              location_checksum,
-                                                              std::move(region),
-                                                              /* verify */ true,
-                                                              /* verify_checksum */ true,
-                                                              &error_message));
+  const ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location,
+                                                               location_checksum,
+                                                               std::move(region),
+                                                               /* verify */ true,
+                                                               /* verify_checksum */ true,
+                                                               &error_message));
   if (expect_success) {
     CHECK(dex_file != nullptr) << error_message;
   } else {
@@ -368,7 +371,8 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  ASSERT_FALSE(dex_file_loader.Open(
       location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
 }
 
@@ -381,7 +385,8 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  ASSERT_FALSE(dex_file_loader.Open(
       location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
 }
 
@@ -394,7 +399,8 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  ASSERT_FALSE(dex_file_loader.Open(
       location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
 }
 
@@ -408,9 +414,10 @@
   std::vector<uint32_t> checksums;
   ScopedObjectAccess soa(Thread::Current());
   std::string error_msg;
-  EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
-                                                  &checksums,
-                                                  &error_msg))
+  const ArtDexFileLoader dex_file_loader;
+  EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
+                                                    &checksums,
+                                                    &error_msg))
       << error_msg;
   ASSERT_EQ(1U, checksums.size());
   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
@@ -420,9 +427,10 @@
   std::string error_msg;
   std::vector<uint32_t> checksums;
   std::string multidex_file = GetTestDexFileName("MultiDex");
-  EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(multidex_file.c_str(),
-                                                  &checksums,
-                                                  &error_msg)) << error_msg;
+  const ArtDexFileLoader dex_file_loader;
+  EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(),
+                                                    &checksums,
+                                                    &error_msg)) << error_msg;
 
   std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
   ASSERT_EQ(2U, dexes.size());
@@ -730,8 +738,10 @@
   std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(
       kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
-  const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
-  CodeItemDebugInfoAccessor accessor(*raw, code_item);
+  constexpr uint32_t kMethodIdx = 1;
+  const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def,
+                                                                                kMethodIdx));
+  CodeItemDebugInfoAccessor accessor(*raw, code_item, kMethodIdx);
   ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
 }
 
diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc
index d4d912c..9759685 100644
--- a/runtime/dex/dex_file_verifier_test.cc
+++ b/runtime/dex/dex_file_verifier_test.cc
@@ -22,6 +22,7 @@
 #include <functional>
 #include <memory>
 
+#include "art_dex_file_loader.h"
 #include "base/bit_utils.h"
 #include "base/macros.h"
 #include "base/unix_file/fd_file.h"
@@ -114,7 +115,8 @@
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
   std::vector<std::unique_ptr<const DexFile>> tmp;
-  bool success = DexFileLoader::Open(
+  const ArtDexFileLoader dex_file_loader;
+  bool success = dex_file_loader.Open(
       location, location, /* verify */ true, /* verify_checksum */ true, error_msg, &tmp);
   CHECK(success) << *error_msg;
   EXPECT_EQ(1U, tmp.size());
diff --git a/runtime/dex/standard_dex_file.h b/runtime/dex/standard_dex_file.h
index fb2f720..6437def 100644
--- a/runtime/dex/standard_dex_file.h
+++ b/runtime/dex/standard_dex_file.h
@@ -33,8 +33,30 @@
   };
 
   struct CodeItem : public DexFile::CodeItem {
+    static constexpr size_t kAlignment = 4;
+
    private:
-    // TODO: Insert standard dex specific fields here.
+    CodeItem() = default;
+
+    uint16_t registers_size_;            // the number of registers used by this code
+                                         //   (locals + parameters)
+    uint16_t ins_size_;                  // the number of words of incoming arguments to the method
+                                         //   that this code is for
+    uint16_t outs_size_;                 // the number of words of outgoing argument space required
+                                         //   by this code for method invocation
+    uint16_t tries_size_;                // the number of try_items for this instance. If non-zero,
+                                         //   then these appear as the tries array just after the
+                                         //   insns in this instance.
+    uint32_t debug_info_off_;            // Holds file offset to debug info stream.
+
+    uint32_t insns_size_in_code_units_;  // size of the insns array, in 2 byte code units
+    uint16_t insns_[1];                  // actual array of bytecode.
+
+    ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+    friend class CodeItemDataAccessor;
+    friend class CodeItemDebugInfoAccessor;
+    friend class CodeItemInstructionAccessor;
+    friend class DexWriter;
     friend class StandardDexFile;
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
   };
@@ -80,6 +102,7 @@
   friend class DexFileVerifierTest;
 
   ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for constructor
+  friend class OptimizingUnitTestHelper;  // for constructor
 
   DISALLOW_COPY_AND_ASSIGN(StandardDexFile);
 };
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index e459f09..20cde53 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -27,6 +27,7 @@
 #include "base/stl_util.h"
 #include "common_runtime_test.h"
 #include "compiler_callbacks.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/heap.h"
@@ -43,6 +44,7 @@
  public:
   virtual void SetUp() OVERRIDE {
     CommonRuntimeTest::SetUp();
+    const ArtDexFileLoader dex_file_loader;
 
     // Create a scratch directory to work from.
 
@@ -74,7 +76,7 @@
     ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
       << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
     ASSERT_FALSE(
-        DexFileLoader::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
+        dex_file_loader.GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
       << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
     ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
       << "Expected dex file to be at: " << GetDexSrc2();
@@ -83,21 +85,21 @@
     // GetMultiDexSrc1, but a different secondary dex checksum.
     static constexpr bool kVerifyChecksum = true;
     std::vector<std::unique_ptr<const DexFile>> multi1;
-    ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc1().c_str(),
-                                    GetMultiDexSrc1().c_str(),
-                                    /* verify */ true,
-                                    kVerifyChecksum,
-                                    &error_msg,
-                                    &multi1)) << error_msg;
+    ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc1().c_str(),
+                                     GetMultiDexSrc1().c_str(),
+                                     /* verify */ true,
+                                     kVerifyChecksum,
+                                     &error_msg,
+                                     &multi1)) << error_msg;
     ASSERT_GT(multi1.size(), 1u);
 
     std::vector<std::unique_ptr<const DexFile>> multi2;
-    ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc2().c_str(),
-                                    GetMultiDexSrc2().c_str(),
-                                    /* verify */ true,
-                                    kVerifyChecksum,
-                                    &error_msg,
-                                    &multi2)) << error_msg;
+    ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc2().c_str(),
+                                     GetMultiDexSrc2().c_str(),
+                                     /* verify */ true,
+                                     kVerifyChecksum,
+                                     &error_msg,
+                                     &multi2)) << error_msg;
     ASSERT_GT(multi2.size(), 1u);
 
     ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
diff --git a/runtime/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
index e1c07ba..7887191 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -36,8 +36,7 @@
                 const ArrayRef<const uint8_t>& quickened_info,
                 bool decompile_return_instruction)
     : code_item_accessor_(dex_file, &code_item),
-      quicken_info_(quickened_info.data()),
-      quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())),
+      quicken_info_(quickened_info),
       decompile_return_instruction_(decompile_return_instruction) {}
 
   bool Decompile();
@@ -72,7 +71,7 @@
   }
 
   uint16_t NextIndex() {
-    DCHECK_LT(quicken_index_, quicken_info_number_of_indices_);
+    DCHECK_LT(quicken_index_, quicken_info_.NumIndices());
     const uint16_t ret = quicken_info_.GetData(quicken_index_);
     quicken_index_++;
     return ret;
@@ -80,7 +79,6 @@
 
   const CodeItemInstructionAccessor code_item_accessor_;
   const QuickenInfoTable quicken_info_;
-  const size_t quicken_info_number_of_indices_;
   const bool decompile_return_instruction_;
 
   size_t quicken_index_ = 0u;
@@ -104,7 +102,7 @@
         break;
 
       case Instruction::NOP:
-        if (quicken_info_number_of_indices_ > 0) {
+        if (quicken_info_.NumIndices() > 0) {
           // Only try to decompile NOP if there are more than 0 indices. Not having
           // any index happens when we unquicken a code item that only has
           // RETURN_VOID_NO_BARRIER as quickened instruction.
@@ -181,14 +179,14 @@
     }
   }
 
-  if (quicken_index_ != quicken_info_number_of_indices_) {
+  if (quicken_index_ != quicken_info_.NumIndices()) {
     if (quicken_index_ == 0) {
       LOG(WARNING) << "Failed to use any value in quickening info,"
                    << " potentially due to duplicate methods.";
     } else {
       LOG(FATAL) << "Failed to use all values in quickening info."
                  << " Actual: " << std::hex << quicken_index_
-                 << " Expected: " << quicken_info_number_of_indices_;
+                 << " Expected: " << quicken_info_.NumIndices();
       return false;
     }
   }
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index cf83716..a68227e 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -88,7 +88,6 @@
       from_space_num_bytes_at_first_pause_(0),
       mark_stack_mode_(kMarkStackModeOff),
       weak_ref_access_enabled_(true),
-      max_peak_num_non_free_regions_(0),
       skipped_blocks_lock_("concurrent copying bytes blocks lock", kMarkSweepMarkStackLock),
       measure_read_barrier_slow_path_(measure_read_barrier_slow_path),
       mark_from_read_barrier_measurements_(false),
@@ -1755,8 +1754,6 @@
     cumulative_bytes_moved_.FetchAndAddRelaxed(to_bytes);
     uint64_t to_objects = objects_moved_.LoadSequentiallyConsistent();
     cumulative_objects_moved_.FetchAndAddRelaxed(to_objects);
-    max_peak_num_non_free_regions_ = std::max(max_peak_num_non_free_regions_,
-                                              region_space_->GetNumNonFreeRegions());
     if (kEnableFromSpaceAccountingCheck) {
       CHECK_EQ(from_space_num_objects_at_first_pause_, from_objects + unevac_from_objects);
       CHECK_EQ(from_space_num_bytes_at_first_pause_, from_bytes + unevac_from_bytes);
@@ -2269,7 +2266,7 @@
   size_t non_moving_space_bytes_allocated = 0U;
   size_t bytes_allocated = 0U;
   size_t dummy;
-  mirror::Object* to_ref = region_space_->AllocNonvirtual<true>(
+  mirror::Object* to_ref = region_space_->AllocNonvirtual</*kForEvac*/ true>(
       region_space_alloc_size, &region_space_bytes_allocated, nullptr, &dummy);
   bytes_allocated = region_space_bytes_allocated;
   if (to_ref != nullptr) {
@@ -2341,7 +2338,7 @@
         DCHECK(region_space_->IsInToSpace(to_ref));
         if (bytes_allocated > space::RegionSpace::kRegionSize) {
           // Free the large alloc.
-          region_space_->FreeLarge(to_ref, bytes_allocated);
+          region_space_->FreeLarge</*kForEvac*/ true>(to_ref, bytes_allocated);
         } else {
           // Record the lost copy for later reuse.
           heap_->num_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes_allocated);
@@ -2696,10 +2693,10 @@
   os << "Cumulative objects moved " << cumulative_objects_moved_.LoadRelaxed() << "\n";
 
   os << "Peak regions allocated "
-     << max_peak_num_non_free_regions_ << " ("
-     << PrettySize(max_peak_num_non_free_regions_ * space::RegionSpace::kRegionSize)
-     << ") / " << region_space_->GetNumRegions() << " ("
-     << PrettySize(region_space_->GetNumRegions() * space::RegionSpace::kRegionSize)
+     << region_space_->GetMaxPeakNumNonFreeRegions() << " ("
+     << PrettySize(region_space_->GetMaxPeakNumNonFreeRegions() * space::RegionSpace::kRegionSize)
+     << ") / " << region_space_->GetNumRegions() / 2 << " ("
+     << PrettySize(region_space_->GetNumRegions() * space::RegionSpace::kRegionSize / 2)
      << ")\n";
 }
 
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 939e7fc..8b4b58e 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -308,11 +308,6 @@
   Atomic<uint64_t> cumulative_bytes_moved_;
   Atomic<uint64_t> cumulative_objects_moved_;
 
-  // Maintain the maximum of number of non-free regions collected just before
-  // reclaim in each GC cycle. At this moment in cycle, highest number of
-  // regions are in non-free.
-  size_t max_peak_num_non_free_regions_;
-
   // The skipped blocks are memory blocks/chucks that were copies of
   // objects that were unused due to lost races (cas failures) at
   // object copy/forward pointer install. They are reused.
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 251d94c..ca5a3ee 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -36,6 +36,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/accounting/space_bitmap-inl.h"
@@ -1828,6 +1829,7 @@
 }
 
 bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) {
+  const ArtDexFileLoader dex_file_loader;
   for (const OatFile::OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
     const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
 
@@ -1838,7 +1840,7 @@
     }
 
     std::vector<uint32_t> checksums;
-    if (!DexFileLoader::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
+    if (!dex_file_loader.GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
       *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
                                 "referenced by oat file %s: %s",
                                 dex_file_location.c_str(),
diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h
index ea2168f..e74e9b1 100644
--- a/runtime/gc/space/region_space-inl.h
+++ b/runtime/gc/space/region_space-inl.h
@@ -115,7 +115,7 @@
 }
 
 template<RegionSpace::RegionType kRegionType>
-uint64_t RegionSpace::GetBytesAllocatedInternal() {
+inline uint64_t RegionSpace::GetBytesAllocatedInternal() {
   uint64_t bytes = 0;
   MutexLock mu(Thread::Current(), region_lock_);
   for (size_t i = 0; i < num_regions_; ++i) {
@@ -150,7 +150,7 @@
 }
 
 template<RegionSpace::RegionType kRegionType>
-uint64_t RegionSpace::GetObjectsAllocatedInternal() {
+inline uint64_t RegionSpace::GetObjectsAllocatedInternal() {
   uint64_t bytes = 0;
   MutexLock mu(Thread::Current(), region_lock_);
   for (size_t i = 0; i < num_regions_; ++i) {
@@ -185,7 +185,7 @@
 }
 
 template<bool kToSpaceOnly, typename Visitor>
-void RegionSpace::WalkInternal(Visitor&& visitor) {
+inline void RegionSpace::WalkInternal(Visitor&& visitor) {
   // TODO: MutexLock on region_lock_ won't work due to lock order
   // issues (the classloader classes lock and the monitor lock). We
   // call this with threads suspended.
@@ -237,9 +237,10 @@
 }
 
 template<bool kForEvac>
-mirror::Object* RegionSpace::AllocLarge(size_t num_bytes, size_t* bytes_allocated,
-                                        size_t* usable_size,
-                                        size_t* bytes_tl_bulk_allocated) {
+inline mirror::Object* RegionSpace::AllocLarge(size_t num_bytes,
+                                               size_t* bytes_allocated,
+                                               size_t* usable_size,
+                                               size_t* bytes_tl_bulk_allocated) {
   DCHECK_ALIGNED(num_bytes, kAlignment);
   DCHECK_GT(num_bytes, kRegionSize);
   size_t num_regs = RoundUp(num_bytes, kRegionSize) / kRegionSize;
@@ -274,7 +275,11 @@
       Region* first_reg = &regions_[left];
       DCHECK(first_reg->IsFree());
       first_reg->UnfreeLarge(this, time_);
-      ++num_non_free_regions_;
+      if (kForEvac) {
+        ++num_evac_regions_;
+      } else {
+        ++num_non_free_regions_;
+      }
       size_t allocated = num_regs * kRegionSize;
       // We make 'top' all usable bytes, as the caller of this
       // allocation may use all of 'usable_size' (see mirror::Array::Alloc).
@@ -283,7 +288,11 @@
         DCHECK_LT(p, num_regions_);
         DCHECK(regions_[p].IsFree());
         regions_[p].UnfreeLargeTail(this, time_);
-        ++num_non_free_regions_;
+        if (kForEvac) {
+          ++num_evac_regions_;
+        } else {
+          ++num_non_free_regions_;
+        }
       }
       *bytes_allocated = allocated;
       if (usable_size != nullptr) {
@@ -299,6 +308,35 @@
   return nullptr;
 }
 
+template<bool kForEvac>
+inline void RegionSpace::FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) {
+  DCHECK(Contains(large_obj));
+  DCHECK_ALIGNED(large_obj, kRegionSize);
+  MutexLock mu(Thread::Current(), region_lock_);
+  uint8_t* begin_addr = reinterpret_cast<uint8_t*>(large_obj);
+  uint8_t* end_addr = AlignUp(reinterpret_cast<uint8_t*>(large_obj) + bytes_allocated, kRegionSize);
+  CHECK_LT(begin_addr, end_addr);
+  for (uint8_t* addr = begin_addr; addr < end_addr; addr += kRegionSize) {
+    Region* reg = RefToRegionLocked(reinterpret_cast<mirror::Object*>(addr));
+    if (addr == begin_addr) {
+      DCHECK(reg->IsLarge());
+    } else {
+      DCHECK(reg->IsLargeTail());
+    }
+    reg->Clear(/*zero_and_release_pages*/true);
+    if (kForEvac) {
+      --num_evac_regions_;
+    } else {
+      --num_non_free_regions_;
+    }
+  }
+  if (end_addr < Limit()) {
+    // If we aren't at the end of the space, check that the next region is not a large tail.
+    Region* following_reg = RefToRegionLocked(reinterpret_cast<mirror::Object*>(end_addr));
+    DCHECK(!following_reg->IsLargeTail());
+  }
+}
+
 inline size_t RegionSpace::Region::BytesAllocated() const {
   if (IsLarge()) {
     DCHECK_LT(begin_ + kRegionSize, Top());
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index a51df7c..45cfff9 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -84,14 +84,18 @@
 RegionSpace::RegionSpace(const std::string& name, MemMap* mem_map)
     : ContinuousMemMapAllocSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
                                  kGcRetentionPolicyAlwaysCollect),
-      region_lock_("Region lock", kRegionSpaceRegionLock), time_(1U) {
-  size_t mem_map_size = mem_map->Size();
-  CHECK_ALIGNED(mem_map_size, kRegionSize);
+      region_lock_("Region lock", kRegionSpaceRegionLock),
+      time_(1U),
+      num_regions_(mem_map->Size() / kRegionSize),
+      num_non_free_regions_(0U),
+      num_evac_regions_(0U),
+      max_peak_num_non_free_regions_(0U),
+      non_free_region_index_limit_(0U),
+      current_region_(&full_region_),
+      evac_region_(nullptr) {
+  CHECK_ALIGNED(mem_map->Size(), kRegionSize);
   CHECK_ALIGNED(mem_map->Begin(), kRegionSize);
-  num_regions_ = mem_map_size / kRegionSize;
-  num_non_free_regions_ = 0U;
   DCHECK_GT(num_regions_, 0U);
-  non_free_region_index_limit_ = 0U;
   regions_.reset(new Region[num_regions_]);
   uint8_t* region_addr = mem_map->Begin();
   for (size_t i = 0; i < num_regions_; ++i, region_addr += kRegionSize) {
@@ -112,8 +116,6 @@
   }
   DCHECK(!full_region_.IsFree());
   DCHECK(full_region_.IsAllocated());
-  current_region_ = &full_region_;
-  evac_region_ = nullptr;
   size_t ignored;
   DCHECK(full_region_.Alloc(kAlignment, &ignored, nullptr, &ignored) == nullptr);
 }
@@ -267,6 +269,9 @@
   VerifyNonFreeRegionLimit();
   size_t new_non_free_region_index_limit = 0;
 
+  // Update max of peak non free region count before reclaiming evacuated regions.
+  max_peak_num_non_free_regions_ = std::max(max_peak_num_non_free_regions_,
+                                            num_non_free_regions_);
   // Combine zeroing and releasing pages to reduce how often madvise is called. This helps
   // reduce contention on the mmap semaphore. b/62194020
   // clear_region adds a region to the current block. If the region is not adjacent, the
@@ -350,6 +355,8 @@
   // Update non_free_region_index_limit_.
   SetNonFreeRegionLimit(new_non_free_region_index_limit);
   evac_region_ = nullptr;
+  num_non_free_regions_ += num_evac_regions_;
+  num_evac_regions_ = 0;
 }
 
 void RegionSpace::LogFragmentationAllocFailure(std::ostream& os,
@@ -411,30 +418,6 @@
       << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(Limit());
 }
 
-void RegionSpace::FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) {
-  DCHECK(Contains(large_obj));
-  DCHECK_ALIGNED(large_obj, kRegionSize);
-  MutexLock mu(Thread::Current(), region_lock_);
-  uint8_t* begin_addr = reinterpret_cast<uint8_t*>(large_obj);
-  uint8_t* end_addr = AlignUp(reinterpret_cast<uint8_t*>(large_obj) + bytes_allocated, kRegionSize);
-  CHECK_LT(begin_addr, end_addr);
-  for (uint8_t* addr = begin_addr; addr < end_addr; addr += kRegionSize) {
-    Region* reg = RefToRegionLocked(reinterpret_cast<mirror::Object*>(addr));
-    if (addr == begin_addr) {
-      DCHECK(reg->IsLarge());
-    } else {
-      DCHECK(reg->IsLargeTail());
-    }
-    reg->Clear(/*zero_and_release_pages*/true);
-    --num_non_free_regions_;
-  }
-  if (end_addr < Limit()) {
-    // If we aren't at the end of the space, check that the next region is not a large tail.
-    Region* following_reg = RefToRegionLocked(reinterpret_cast<mirror::Object*>(end_addr));
-    DCHECK(!following_reg->IsLargeTail());
-  }
-}
-
 void RegionSpace::DumpRegions(std::ostream& os) {
   MutexLock mu(Thread::Current(), region_lock_);
   for (size_t i = 0; i < num_regions_; ++i) {
@@ -572,10 +555,12 @@
     Region* r = &regions_[i];
     if (r->IsFree()) {
       r->Unfree(this, time_);
-      ++num_non_free_regions_;
-      if (!for_evac) {
+      if (for_evac) {
+        ++num_evac_regions_;
         // Evac doesn't count as newly allocated.
+      } else {
         r->SetNewlyAllocated();
+        ++num_non_free_regions_;
       }
       return r;
     }
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index c9c9136..ef8aa52 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -64,6 +64,7 @@
   template<bool kForEvac>
   mirror::Object* AllocLarge(size_t num_bytes, size_t* bytes_allocated, size_t* usable_size,
                              size_t* bytes_tl_bulk_allocated) REQUIRES(!region_lock_);
+  template<bool kForEvac>
   void FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) REQUIRES(!region_lock_);
 
   // Return the storage space required by obj.
@@ -138,9 +139,8 @@
   uint64_t GetObjectsAllocatedInUnevacFromSpace() REQUIRES(!region_lock_) {
     return GetObjectsAllocatedInternal<RegionType::kRegionTypeUnevacFromSpace>();
   }
-  // It is OK to do a racy read here as it's only for performance dump.
-  size_t GetNumNonFreeRegions() const {
-    return num_non_free_regions_;
+  size_t GetMaxPeakNumNonFreeRegions() const {
+    return max_peak_num_non_free_regions_;
   }
   size_t GetNumRegions() const {
     return num_regions_;
@@ -530,8 +530,18 @@
   Mutex region_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
 
   uint32_t time_;                  // The time as the number of collections since the startup.
-  size_t num_regions_;             // The number of regions in this space.
-  size_t num_non_free_regions_;    // The number of non-free regions in this space.
+  const size_t num_regions_;       // The number of regions in this space.
+  // The number of non-free regions in this space.
+  size_t num_non_free_regions_ GUARDED_BY(region_lock_);
+
+  // The number of evac regions allocated during collection. 0 when GC not running.
+  size_t num_evac_regions_ GUARDED_BY(region_lock_);
+
+  // Maintain the maximum of number of non-free regions collected just before
+  // reclaim in each GC cycle. At this moment in cycle, highest number of
+  // regions are in non-free.
+  size_t max_peak_num_non_free_regions_;
+
   std::unique_ptr<Region[]> regions_ GUARDED_BY(region_lock_);
                                    // The pointer to the region array.
   // The upper-bound index of the non-free regions. Used to avoid scanning all regions in
diff --git a/runtime/globals.h b/runtime/globals.h
index f14d6e9..ca4040d 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -62,6 +62,12 @@
 static constexpr bool kIsDebugBuild = GlobalsReturnSelf(true);
 #endif
 
+#if defined(ART_PGO_INSTRUMENTATION)
+static constexpr bool kIsPGOInstrumentation = true;
+#else
+static constexpr bool kIsPGOInstrumentation = false;
+#endif
+
 // ART_TARGET - Defined for target builds of ART.
 // ART_TARGET_LINUX - Defined for target Linux builds of ART.
 // ART_TARGET_ANDROID - Defined for target Android builds of ART.
diff --git a/runtime/image.cc b/runtime/image.cc
index b9d955c..dd0c148 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '2', '\0' };  // 4-bit ClassStatus.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '3', '\0' };  // ClassStatus in high bits.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 8abf8a6..55e9c39 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -927,9 +927,6 @@
   UNUSED(low_4gb);
 #endif
   DCHECK_ALIGNED(length, kPageSize);
-  if (low_4gb) {
-    DCHECK_EQ(flags & MAP_FIXED, 0);
-  }
   // TODO:
   // A page allocator would be a useful abstraction here, as
   // 1) It is doubtful that MAP_32BIT on x86_64 is doing the right job for us
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 55c5889..84b0326 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -81,9 +81,9 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
     // Avoid including "subtype_check_bits_and_status.h" to get the field.
-    // The ClassStatus is always in the least-significant bits of status_.
+    // The ClassStatus is always in the 4 most-significant of status_.
     return enum_cast<ClassStatus>(
-        static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff);
+        static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) >> (32 - 4));
   }
 
   // This is static because 'this' may be moved by GC.
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index a992b5c..0f43087 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -27,6 +27,7 @@
 #include <class_loader_context.h>
 #include "common_throws.h"
 #include "compiler_filter.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "jni_internal.h"
@@ -188,12 +189,13 @@
                                       dex_mem_map->Begin(),
                                       dex_mem_map->End());
   std::string error_message;
-  std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
-                                                              0,
-                                                              std::move(dex_mem_map),
-                                                              /* verify */ true,
-                                                              /* verify_location */ true,
-                                                              &error_message));
+  const ArtDexFileLoader dex_file_loader;
+  std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location,
+                                                               0,
+                                                               std::move(dex_mem_map),
+                                                               /* verify */ true,
+                                                               /* verify_location */ true,
+                                                               &error_message));
   if (dex_file == nullptr) {
     ScopedObjectAccess soa(env);
     ThrowWrappedIOException("%s", error_message.c_str());
diff --git a/runtime/oat.h b/runtime/oat.h
index 6d4f18b..36099b9 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  // Last oat version changed reason: 4-bit ClassStatus.
-  static constexpr uint8_t kOatVersion[] = { '1', '3', '6', '\0' };
+  // Last oat version changed reason: ClassStatus in high bits.
+  static constexpr uint8_t kOatVersion[] = { '1', '3', '7', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index df07a19..c03dbcc 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -43,6 +43,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_file_types.h"
 #include "dex/standard_dex_file.h"
@@ -194,10 +195,6 @@
 
   ret->PreLoad();
 
-  if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
-    return nullptr;
-  }
-
   if (!ret->Load(elf_filename,
                  oat_file_begin,
                  writable,
@@ -211,6 +208,10 @@
     return nullptr;
   }
 
+  if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
+    return nullptr;
+  }
+
   ret->PreSetup(elf_filename);
 
   if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -234,10 +235,6 @@
                                       std::string* error_msg) {
   std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
 
-  if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
-    return nullptr;
-  }
-
   if (!ret->Load(oat_fd,
                  oat_file_begin,
                  writable,
@@ -251,6 +248,10 @@
     return nullptr;
   }
 
+  if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
+    return nullptr;
+  }
+
   ret->PreSetup(oat_location);
 
   if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -264,7 +265,14 @@
                            bool writable,
                            bool low_4gb,
                            std::string* error_msg) {
-  vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg);
+  vdex_ = VdexFile::OpenAtAddress(vdex_begin_,
+                                  vdex_end_ - vdex_begin_,
+                                  vdex_begin_ != nullptr /* mmap_reuse */,
+                                  vdex_filename,
+                                  writable,
+                                  low_4gb,
+                                  /* unquicken*/ false,
+                                  error_msg);
   if (vdex_.get() == nullptr) {
     *error_msg = StringPrintf("Failed to load vdex file '%s' %s",
                               vdex_filename.c_str(),
@@ -285,13 +293,16 @@
     if (rc == -1) {
       PLOG(WARNING) << "Failed getting length of vdex file";
     } else {
-      vdex_ = VdexFile::Open(vdex_fd,
-                             s.st_size,
-                             vdex_filename,
-                             writable,
-                             low_4gb,
-                             false /* unquicken */,
-                             error_msg);
+      vdex_ = VdexFile::OpenAtAddress(vdex_begin_,
+                                      vdex_end_ - vdex_begin_,
+                                      vdex_begin_ != nullptr /* mmap_reuse */,
+                                      vdex_fd,
+                                      s.st_size,
+                                      vdex_filename,
+                                      writable,
+                                      low_4gb,
+                                      false /* unquicken */,
+                                      error_msg);
       if (vdex_.get() == nullptr) {
         *error_msg = "Failed opening vdex file.";
         return false;
@@ -339,7 +350,7 @@
   } else {
     bss_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbsslastword", &symbol_error_msg));
     if (bss_end_ == nullptr) {
-      *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", file_path.c_str());
+      *error_msg = StringPrintf("Failed to find oatbsslastword symbol in '%s'", file_path.c_str());
       return false;
     }
     // Readjust to be non-inclusive upper bound.
@@ -351,6 +362,20 @@
     bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg));
   }
 
+  vdex_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdex", &symbol_error_msg));
+  if (vdex_begin_ == nullptr) {
+    // No .vdex section.
+    vdex_end_ = nullptr;
+  } else {
+    vdex_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdexlastword", &symbol_error_msg));
+    if (vdex_end_ == nullptr) {
+      *error_msg = StringPrintf("Failed to find oatdexlastword symbol in '%s'", file_path.c_str());
+      return false;
+    }
+    // Readjust to be non-inclusive upper bound.
+    vdex_end_ += sizeof(uint32_t);
+  }
+
   return true;
 }
 
@@ -1441,6 +1466,8 @@
       bss_methods_(nullptr),
       bss_roots_(nullptr),
       is_executable_(is_executable),
+      vdex_begin_(nullptr),
+      vdex_end_(nullptr),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
   CHECK(!location_.empty());
 }
@@ -1471,6 +1498,14 @@
   return bss_end_;
 }
 
+const uint8_t* OatFile::VdexBegin() const {
+  return vdex_begin_;
+}
+
+const uint8_t* OatFile::VdexEnd() const {
+  return vdex_end_;
+}
+
 const uint8_t* OatFile::DexBegin() const {
   return vdex_->Begin();
 }
@@ -1500,21 +1535,6 @@
   }
 }
 
-uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) {
-  // Note that although the specification says that 0 should be used if there
-  // is no debug information, some applications incorrectly use 0xFFFFFFFF.
-  // The following check also handles debug_info_off == 0.
-  if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) {
-    return debug_info_off;
-  }
-  const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
-  if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
-    return debug_info_off;
-  }
-  return oat_dex_file->GetOatFile()->GetVdexFile()->GetDebugInfoOffset(
-      dex_file, debug_info_off);
-}
-
 const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
                                                   const uint32_t* dex_location_checksum,
                                                   std::string* error_msg) const {
@@ -1632,14 +1652,15 @@
   ScopedTrace trace(__PRETTY_FUNCTION__);
   static constexpr bool kVerify = false;
   static constexpr bool kVerifyChecksum = false;
-  return DexFileLoader::Open(dex_file_pointer_,
-                             FileSize(),
-                             dex_file_location_,
-                             dex_file_location_checksum_,
-                             this,
-                             kVerify,
-                             kVerifyChecksum,
-                             error_msg);
+  const ArtDexFileLoader dex_file_loader;
+  return dex_file_loader.Open(dex_file_pointer_,
+                              FileSize(),
+                              dex_file_location_,
+                              dex_file_location_checksum_,
+                              this,
+                              kVerify,
+                              kVerifyChecksum,
+                              error_msg);
 }
 
 uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 02318b6..bf22e0b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -115,10 +115,6 @@
                                const char* abs_dex_location,
                                std::string* error_msg);
 
-  // Return the actual debug info offset for an offset that might be actually pointing to
-  // dequickening info. The returned debug info offset is the one originally in the the dex file.
-  static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);
-
   virtual ~OatFile();
 
   bool IsExecutable() const {
@@ -279,6 +275,10 @@
     return BssEnd() - BssBegin();
   }
 
+  size_t VdexSize() const {
+    return VdexEnd() - VdexBegin();
+  }
+
   size_t BssMethodsOffset() const {
     // Note: This is used only for symbolizer and needs to return a valid .bss offset.
     return (bss_methods_ != nullptr) ? bss_methods_ - BssBegin() : BssRootsOffset();
@@ -299,6 +299,9 @@
   const uint8_t* BssBegin() const;
   const uint8_t* BssEnd() const;
 
+  const uint8_t* VdexBegin() const;
+  const uint8_t* VdexEnd() const;
+
   const uint8_t* DexBegin() const;
   const uint8_t* DexEnd() const;
 
@@ -358,6 +361,12 @@
   // Was this oat_file loaded executable?
   const bool is_executable_;
 
+  // Pointer to the .vdex section, if present, otherwise null.
+  uint8_t* vdex_begin_;
+
+  // Pointer to the end of the .vdex section, if present, otherwise null.
+  uint8_t* vdex_end_;
+
   // Owning storage for the OatDexFile objects.
   std::vector<const OatDexFile*> oat_dex_files_storage_;
 
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 240030c..73ca19a 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -28,6 +28,7 @@
 #include "base/stl_util.h"
 #include "class_linker.h"
 #include "compiler_filter.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/heap.h"
@@ -869,10 +870,11 @@
     required_dex_checksums_found_ = false;
     cached_required_dex_checksums_.clear();
     std::string error_msg;
-    if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(),
-                                            &cached_required_dex_checksums_,
-                                            &error_msg,
-                                            zip_fd_)) {
+    const ArtDexFileLoader dex_file_loader;
+    if (dex_file_loader.GetMultiDexChecksums(dex_location_.c_str(),
+                                             &cached_required_dex_checksums_,
+                                             &error_msg,
+                                             zip_fd_)) {
       required_dex_checksums_found_ = true;
       has_original_dex_files_ = true;
     } else {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 577f8be..9503360 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -31,6 +31,7 @@
 #include "base/systrace.h"
 #include "class_linker.h"
 #include "class_loader_context.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_file_tracking_registrar.h"
@@ -613,12 +614,13 @@
     if (oat_file_assistant.HasOriginalDexFiles()) {
       if (Runtime::Current()->IsDexFileFallbackEnabled()) {
         static constexpr bool kVerifyChecksum = true;
-        if (!DexFileLoader::Open(dex_location,
-                                 dex_location,
-                                 Runtime::Current()->IsVerificationEnabled(),
-                                 kVerifyChecksum,
-                                 /*out*/ &error_msg,
-                                 &dex_files)) {
+        const ArtDexFileLoader dex_file_loader;
+        if (!dex_file_loader.Open(dex_location,
+                                  dex_location,
+                                  Runtime::Current()->IsVerificationEnabled(),
+                                  kVerifyChecksum,
+                                  /*out*/ &error_msg,
+                                  &dex_files)) {
           LOG(WARNING) << error_msg;
           error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
                                 + " because: " + error_msg);
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index 7bf0f84..8d86401 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -21,11 +21,13 @@
 #include <gtest/gtest.h>
 
 #include "common_runtime_test.h"
+#include "dexopt_test.h"
 #include "scoped_thread_state_change-inl.h"
+#include "vdex_file.h"
 
 namespace art {
 
-class OatFileTest : public CommonRuntimeTest {
+class OatFileTest : public DexoptTest {
 };
 
 TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) {
@@ -62,4 +64,28 @@
         "/data/app/foo/base.apk", "o/base.apk"));
 }
 
+TEST_F(OatFileTest, LoadOat) {
+  std::string dex_location = GetScratchDir() + "/LoadOat.jar";
+
+  Copy(GetDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+
+  std::string oat_location;
+  std::string error_msg;
+  ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
+        dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
+  std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(),
+                                                   oat_location.c_str(),
+                                                   nullptr,
+                                                   nullptr,
+                                                   false,
+                                                   /*low_4gb*/false,
+                                                   dex_location.c_str(),
+                                                   &error_msg));
+  ASSERT_TRUE(odex_file.get() != nullptr);
+
+  // Check that the vdex file was loaded in the reserved space of odex file.
+  EXPECT_EQ(odex_file->GetVdexFile()->Begin(), odex_file->VdexBegin());
+}
+
 }  // namespace art
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index 70e767a..14fdba3 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -37,7 +37,7 @@
 template<class MirrorType>
 class ObjPtr {
   static constexpr size_t kCookieShift =
-      sizeof(kHeapReferenceSize) * kBitsPerByte - kObjectAlignmentShift;
+      kHeapReferenceSize * kBitsPerByte - kObjectAlignmentShift;
   static constexpr size_t kCookieBits = sizeof(uintptr_t) * kBitsPerByte - kCookieShift;
   static constexpr uintptr_t kCookieMask = (static_cast<uintptr_t>(1u) << kCookieBits) - 1;
 
diff --git a/runtime/quicken_info.h b/runtime/quicken_info.h
index ce11f3c..52eca61 100644
--- a/runtime/quicken_info.h
+++ b/runtime/quicken_info.h
@@ -17,15 +17,93 @@
 #ifndef ART_RUNTIME_QUICKEN_INFO_H_
 #define ART_RUNTIME_QUICKEN_INFO_H_
 
+#include "base/array_ref.h"
 #include "dex/dex_instruction.h"
+#include "leb128.h"
 
 namespace art {
 
-// QuickenInfoTable is a table of 16 bit dex indices. There is one slot fo every instruction that is
-// possibly dequickenable.
+// Table for getting the offset of quicken info. Doesn't have one slot for each index, so a
+// combination of iteration and indexing is required to get the quicken info for a given dex method
+// index.
+class QuickenInfoOffsetTableAccessor {
+ public:
+  using TableType = uint32_t;
+  static constexpr uint32_t kElementsPerIndex = 16;
+
+  class Builder {
+   public:
+    explicit Builder(std::vector<uint8_t>* out_data) : out_data_(out_data) {}
+
+    void AddOffset(uint32_t index) {
+      out_data_->insert(out_data_->end(),
+                        reinterpret_cast<const uint8_t*>(&index),
+                        reinterpret_cast<const uint8_t*>(&index + 1));
+    }
+
+   private:
+    std::vector<uint8_t>* const out_data_;
+  };
+
+  // The table only covers every kElementsPerIndex indices.
+  static bool IsCoveredIndex(uint32_t index) {
+    return index % kElementsPerIndex == 0;
+  }
+
+  explicit QuickenInfoOffsetTableAccessor(const uint8_t* data, uint32_t max_index)
+      : table_(reinterpret_cast<const uint32_t*>(data)),
+        num_indices_(RoundUp(max_index, kElementsPerIndex) / kElementsPerIndex) {}
+
+  size_t SizeInBytes() const {
+    return NumIndices() * sizeof(table_[0]);
+  }
+
+  uint32_t NumIndices() const {
+    return num_indices_;
+  }
+
+  // Returns the offset for the index at or before the desired index. If the offset is for an index
+  // before the desired one, remainder is how many elements to traverse to reach the desired index.
+  TableType ElementOffset(uint32_t index, uint32_t* remainder) const {
+    *remainder = index % kElementsPerIndex;
+    return table_[index / kElementsPerIndex];
+  }
+
+  const uint8_t* DataEnd() const {
+    return reinterpret_cast<const uint8_t*>(table_ + NumIndices());
+  }
+
+  static uint32_t Alignment() {
+    return alignof(TableType);
+  }
+
+ private:
+  const TableType* table_;
+  uint32_t num_indices_;
+};
+
+// QuickenInfoTable is a table of 16 bit dex indices. There is one slot for every instruction that
+// is possibly dequickenable.
 class QuickenInfoTable {
  public:
-  explicit QuickenInfoTable(const uint8_t* data) : data_(data) {}
+  class Builder {
+   public:
+    Builder(std::vector<uint8_t>* out_data, size_t num_elements) : out_data_(out_data) {
+      EncodeUnsignedLeb128(out_data_, num_elements);
+    }
+
+    void AddIndex(uint16_t index) {
+      out_data_->push_back(static_cast<uint8_t>(index));
+      out_data_->push_back(static_cast<uint8_t>(index >> 8));
+    }
+
+   private:
+    std::vector<uint8_t>* const out_data_;
+  };
+
+  explicit QuickenInfoTable(ArrayRef<const uint8_t> data)
+      : data_(data.data()),
+        num_elements_(!data.empty() ? DecodeUnsignedLeb128(&data_) : 0u) {}
 
   bool IsNull() const {
     return data_ == nullptr;
@@ -44,8 +122,18 @@
     return bytes / sizeof(uint16_t);
   }
 
+  static size_t SizeInBytes(ArrayRef<const uint8_t> data) {
+    QuickenInfoTable table(data);
+    return table.data_ + table.NumIndices() * 2 - data.data();
+  }
+
+  uint32_t NumIndices() const {
+    return num_elements_;
+  }
+
  private:
-  const uint8_t* const data_;
+  const uint8_t* data_;
+  const uint32_t num_elements_;
 
   DISALLOW_COPY_AND_ASSIGN(QuickenInfoTable);
 };
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1bddb4e..377e0a3 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -69,6 +69,7 @@
 #include "class_linker-inl.h"
 #include "compiler_callbacks.h"
 #include "debugger.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file_loader.h"
 #include "elf_file.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
@@ -1041,6 +1042,7 @@
   if (!image_location.empty() && OpenDexFilesFromImage(image_location, dex_files, &failure_count)) {
     return failure_count;
   }
+  const ArtDexFileLoader dex_file_loader;
   failure_count = 0;
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i].c_str();
@@ -1051,12 +1053,12 @@
       LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
       continue;
     }
-    if (!DexFileLoader::Open(dex_filename,
-                             dex_location,
-                             Runtime::Current()->IsVerificationEnabled(),
-                             kVerifyChecksum,
-                             &error_msg,
-                             dex_files)) {
+    if (!dex_file_loader.Open(dex_filename,
+                              dex_location,
+                              Runtime::Current()->IsVerificationEnabled(),
+                              kVerifyChecksum,
+                              &error_msg,
+                              dex_files)) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     }
diff --git a/runtime/subtype_check_bits.h b/runtime/subtype_check_bits.h
index 4305ff8..462f203 100644
--- a/runtime/subtype_check_bits.h
+++ b/runtime/subtype_check_bits.h
@@ -26,22 +26,22 @@
 /**
  * The SubtypeCheckBits memory layout (in bits):
  *
- *                                 Variable
- *                                     |
- *        <---- up to 23 bits ---->    v               +---> 1 bit
- *                                                     |
- *  +-------------------------+--------+-----------+---++
- *  |             Bitstring                        |    |
- *  +-------------------------+--------+-----------+    |
- *  |      Path To Root       |  Next  | (unused)  | OF |
- *  +---+---------------------+--------+           |    |
- *  |   |    |    |    | ...  |        | (0....0)  |    |
- *  +---+---------------------+--------+-----------+----+
- * MSB                                                LSB
+ *   1 bit       Variable
+ *     |             |
+ *     v             v     <---- up to 23 bits ---->
+ *
+ *  +----+-----------+--------+-------------------------+
+ *  |    |                  Bitstring                   |
+ *  +    +-----------+--------+-------------------------+
+ *  | OF | (unused)  |  Next  |      Path To Root       |
+ *  +    |           |--------+----+----------+----+----+
+ *  |    | (0....0)  |        |    |   ...    |    |    |
+ *  +----+-----------+--------+----+----------+----+----+
+ * MSB (most significant bit)                          LSB
  *
  * The bitstring takes up to 23 bits; anything exceeding that is truncated:
  * - Path To Root is a list of chars, encoded as a BitString:
- *     starting at the root (in MSB), each character is a sibling index unique to the parent,
+ *     starting at the root (in LSB), each character is a sibling index unique to the parent,
  *   Paths longer than BitString::kCapacity are truncated to fit within the BitString.
  * - Next is a single BitStringChar (immediatelly following Path To Root)
  *     When new children are assigned paths, they get allocated the parent's Next value.
@@ -57,8 +57,8 @@
  * See subtype_check.h and subtype_check_info.h for more details.
  */
 BITSTRUCT_DEFINE_START(SubtypeCheckBits, /*size*/ BitString::BitStructSizeOf() + 1u)
-  BitStructUint</*lsb*/0, /*width*/1> overflow_;
-  BitStructField<BitString, /*lsb*/1> bitstring_;
+  BitStructField<BitString, /*lsb*/ 0> bitstring_;
+  BitStructUint</*lsb*/ BitString::BitStructSizeOf(), /*width*/ 1> overflow_;
 BITSTRUCT_DEFINE_END(SubtypeCheckBits);
 
 }  // namespace art
diff --git a/runtime/subtype_check_bits_and_status.h b/runtime/subtype_check_bits_and_status.h
index 11cb9b9..321a723 100644
--- a/runtime/subtype_check_bits_and_status.h
+++ b/runtime/subtype_check_bits_and_status.h
@@ -19,6 +19,7 @@
 
 #include "base/bit_struct.h"
 #include "base/bit_utils.h"
+#include "base/casts.h"
 #include "class_status.h"
 #include "subtype_check_bits.h"
 
@@ -36,13 +37,13 @@
 }
 
 /**
- *  MSB                                                                  LSB
- *  +---------------------------------------------------+---------------+
- *  |                                                   |               |
- *  |                 SubtypeCheckBits                  |  ClassStatus  |
- *  |                                                   |               |
- *  +---------------------------------------------------+---------------+
- *            <-----     24 bits     ----->               <-- 8 bits -->
+ * MSB (most significant bit)                                          LSB
+ *  +---------------+---------------------------------------------------+
+ *  |               |                                                   |
+ *  |  ClassStatus  |                 SubtypeCheckBits                  |
+ *  |               |                                                   |
+ *  +---------------+---------------------------------------------------+
+ *   <-- 4 bits -->             <-----     28 bits     ----->
  *
  * Invariants:
  *
@@ -53,20 +54,25 @@
  * This enables a highly efficient path comparison between any two labels:
  *
  * src <: target :=
- *   src >> (32 - len(path-to-root(target))) == target >> (32 - len(path-to-root(target))
+ *   (src & mask) == (target & mask)  where  mask := (1u << len(path-to-root(target)) - 1u
  *
- * In the above example, the RHS operands are a function of the depth. Since the target
- * is known at compile time, it becomes:
- *
- *   src >> #imm_target_shift == #imm
+ * In the above example, the `len()` (and thus `mask`) is a function of the depth.
+ * Since the target is known at compile time, it becomes
+ *   (src & #imm_mask) == #imm
+ * or
+ *   ((src - #imm) << #imm_shift_to_remove_high_bits) == 0
+ * or a similar expression chosen for the best performance or code size.
  *
  * (This requires that path-to-root in `target` is not truncated, i.e. it is in the Assigned state).
  */
-static constexpr size_t kClassStatusBitSize = 8u;  // NonNumericBitSizeOf<ClassStatus>()
+static constexpr size_t kClassStatusBitSize = MinimumBitsToStore(enum_cast<>(ClassStatus::kLast));
+static_assert(kClassStatusBitSize == 4u, "ClassStatus should need 4 bits.");
 BITSTRUCT_DEFINE_START(SubtypeCheckBitsAndStatus, BitSizeOf<BitString::StorageType>())
-  BitStructField<ClassStatus, /*lsb*/0, /*width*/kClassStatusBitSize> status_;
-  BitStructField<SubtypeCheckBits, /*lsb*/kClassStatusBitSize> subtype_check_info_;
-  BitStructInt</*lsb*/0, /*width*/BitSizeOf<BitString::StorageType>()> int32_alias_;
+  BitStructField<SubtypeCheckBits, /*lsb*/ 0> subtype_check_info_;
+  BitStructField<ClassStatus,
+                 /*lsb*/ SubtypeCheckBits::BitStructSizeOf(),
+                 /*width*/ kClassStatusBitSize> status_;
+  BitStructInt</*lsb*/ 0, /*width*/ BitSizeOf<BitString::StorageType>()> int32_alias_;
 BITSTRUCT_DEFINE_END(SubtypeCheckBitsAndStatus);
 
 // Use the spare alignment from "ClassStatus" to store all the new SubtypeCheckInfo data.
diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h
index 61d590b..08db770 100644
--- a/runtime/subtype_check_info.h
+++ b/runtime/subtype_check_info.h
@@ -296,8 +296,7 @@
   BitString::StorageType GetEncodedPathToRoot() const {
     BitString::StorageType data = static_cast<BitString::StorageType>(GetPathToRoot());
     // Bit strings are logically in the least-significant memory.
-    // Shift it so the bits are all most-significant.
-    return data << (BitSizeOf(data) - BitStructSizeOf<BitString>());
+    return data;
   }
 
   // Retrieve the path to root bitstring mask as a plain uintN_t that is amenable to
@@ -305,17 +304,7 @@
   BitString::StorageType GetEncodedPathToRootMask() const {
     size_t num_bitchars = GetSafeDepth();
     size_t bitlength = BitString::GetBitLengthTotalAtPosition(num_bitchars);
-
-    BitString::StorageType mask_all =
-        std::numeric_limits<BitString::StorageType>::max();
-    BitString::StorageType mask_lsb =
-        MaskLeastSignificant<BitString::StorageType>(
-            BitSizeOf<BitString::StorageType>() - bitlength);
-
-    BitString::StorageType result = mask_all & ~mask_lsb;
-
-    // TODO: refactor above code into MaskMostSignificant?
-    return result;
+    return MaskLeastSignificant<BitString::StorageType>(bitlength);
   }
 
   // Get the "Next" bitchar, assuming that there is one to get.
diff --git a/runtime/subtype_check_info_test.cc b/runtime/subtype_check_info_test.cc
index 338d75a..91fcc07 100644
--- a/runtime/subtype_check_info_test.cc
+++ b/runtime/subtype_check_info_test.cc
@@ -65,7 +65,7 @@
   return uint_value;
 }
 
-// Make max bistring, e.g. BitString[4095,7,255] for {12,3,8}
+// Make max bistring, e.g. BitString[4095,15,2047] for {12,4,11}
 template <size_t kCount = BitString::kCapacity>
 BitString MakeBitStringMax() {
   BitString bs{};
@@ -258,60 +258,62 @@
 TEST_F(SubtypeCheckInfoTest, EncodedPathToRoot) {
   using StorageType = BitString::StorageType;
 
-  SubtypeCheckInfo io =
+  SubtypeCheckInfo sci =
       MakeSubtypeCheckInfo(/*path_to_root*/MakeBitStringMax(),
                            /*next*/BitStringChar{},
                            /*overflow*/false,
                            /*depth*/BitString::kCapacity);
-  // 0b11111...000 where MSB == 1, and leading 1s = the maximum bitstring representation.
-  EXPECT_EQ(MaxInt<StorageType>(LenForPos()) << (BitSizeOf<StorageType>() - LenForPos()),
-            io.GetEncodedPathToRoot());
-
-  EXPECT_EQ(MaxInt<StorageType>(LenForPos()) << (BitSizeOf<StorageType>() - LenForPos()),
-            io.GetEncodedPathToRootMask());
-
-  // 0b11111...000 where MSB == 1, and leading 1s = the maximum bitstring representation.
+  // 0b000...111 where LSB == 1, and trailing 1s = the maximum bitstring representation.
+  EXPECT_EQ(MaxInt<StorageType>(LenForPos()), sci.GetEncodedPathToRoot());
 
   // The rest of this test is written assuming kCapacity == 3 for convenience.
   // Please update the test if this changes.
   ASSERT_EQ(3u, BitString::kCapacity);
   ASSERT_EQ(12u, BitString::kBitSizeAtPosition[0]);
-  ASSERT_EQ(3u, BitString::kBitSizeAtPosition[1]);
-  ASSERT_EQ(8u, BitString::kBitSizeAtPosition[2]);
+  ASSERT_EQ(4u, BitString::kBitSizeAtPosition[1]);
+  ASSERT_EQ(11u, BitString::kBitSizeAtPosition[2]);
 
-  SubtypeCheckInfo io2 =
+  SubtypeCheckInfo sci2 =
       MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
                                    /*overflow*/false,
                                    /*depth*/BitString::kCapacity);
 
-#define MAKE_ENCODED_PATH(pos0, pos1, pos2) (((pos0) << 3u << 8u << 9u) | ((pos1) << 8u << 9u) | ((pos2) << 9u))
+#define MAKE_ENCODED_PATH(pos0, pos1, pos2) \
+    (((pos0) << 0) | \
+     ((pos1) << BitString::kBitSizeAtPosition[0]) | \
+     ((pos2) << (BitString::kBitSizeAtPosition[0] + BitString::kBitSizeAtPosition[1])))
 
-  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io2.GetEncodedPathToRoot());
-  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b11111111), io2.GetEncodedPathToRootMask());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
+            sci2.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b11111111111),
+            sci2.GetEncodedPathToRootMask());
 
-  SubtypeCheckInfo io3 =
+  SubtypeCheckInfo sci3 =
       MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
                                    /*overflow*/false,
                                    /*depth*/BitString::kCapacity - 1u);
 
-  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io3.GetEncodedPathToRoot());
-  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io3.GetEncodedPathToRootMask());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
+            sci3.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
+            sci3.GetEncodedPathToRootMask());
 
-  SubtypeCheckInfo io4 =
+  SubtypeCheckInfo sci4 =
       MakeSubtypeCheckInfoUnchecked(MakeBitString({0b1010101u}),
                                    /*overflow*/false,
                                    /*depth*/BitString::kCapacity - 2u);
 
-  EXPECT_EQ(MAKE_ENCODED_PATH(0b1010101u, 0b000, 0b0), io4.GetEncodedPathToRoot());
-  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b000, 0b0), io4.GetEncodedPathToRootMask());
+  EXPECT_EQ(MAKE_ENCODED_PATH(0b1010101u, 0b0000, 0b0), sci4.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b0000, 0b0),
+            sci4.GetEncodedPathToRootMask());
 }
 
 TEST_F(SubtypeCheckInfoTest, NewForRoot) {
-  SubtypeCheckInfo io = SubtypeCheckInfo::CreateRoot();
-  EXPECT_EQ(SubtypeCheckInfo::kAssigned, io.GetState());  // Root is always assigned.
-  EXPECT_EQ(0u, GetPathToRoot(io).Length());  // Root's path length is 0.
-  EXPECT_TRUE(HasNext(io));  // Root always has a "Next".
-  EXPECT_EQ(MakeBitStringChar(1u), io.GetNext());  // Next>=1 to disambiguate from Uninitialized.
+  SubtypeCheckInfo sci = SubtypeCheckInfo::CreateRoot();
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned, sci.GetState());  // Root is always assigned.
+  EXPECT_EQ(0u, GetPathToRoot(sci).Length());  // Root's path length is 0.
+  EXPECT_TRUE(HasNext(sci));  // Root always has a "Next".
+  EXPECT_EQ(MakeBitStringChar(1u), sci.GetNext());  // Next>=1 to disambiguate from Uninitialized.
 }
 
 TEST_F(SubtypeCheckInfoTest, CopyCleared) {
diff --git a/runtime/utils.cc b/runtime/utils.cc
index bd4175f..79ddcb9 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -26,10 +26,10 @@
 
 #include <memory>
 
+#include "android-base/file.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
-#include "base/file_utils.h"
 #include "dex/dex_file-inl.h"
 #include "os.h"
 #include "utf-inl.h"
@@ -46,6 +46,7 @@
 
 namespace art {
 
+using android::base::ReadFileToString;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
 
@@ -63,6 +64,7 @@
 
 std::string GetThreadName(pid_t tid) {
   std::string result;
+  // TODO: make this less Linux-specific.
   if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) {
     result.resize(result.size() - 1);  // Lose the trailing '\n'.
   } else {
@@ -611,6 +613,7 @@
 void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) {
   *utime = *stime = *task_cpu = 0;
   std::string stats;
+  // TODO: make this less Linux-specific.
   if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
     return;
   }
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index a53556f..118cffe 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -25,9 +25,11 @@
 #include "base/bit_utils.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "dex_to_dex_decompiler.h"
+#include "quicken_info.h"
 
 namespace art {
 
@@ -57,11 +59,14 @@
   DCHECK(IsVersionValid());
 }
 
-std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
-                                         bool writable,
-                                         bool low_4gb,
-                                         bool unquicken,
-                                         std::string* error_msg) {
+std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
+                                                  size_t mmap_size,
+                                                  bool mmap_reuse,
+                                                  const std::string& vdex_filename,
+                                                  bool writable,
+                                                  bool low_4gb,
+                                                  bool unquicken,
+                                                  std::string* error_msg) {
   if (!OS::FileExists(vdex_filename.c_str())) {
     *error_msg = "File " + vdex_filename + " does not exist.";
     return nullptr;
@@ -85,23 +90,43 @@
     return nullptr;
   }
 
-  return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
+  return OpenAtAddress(mmap_addr,
+                       mmap_size,
+                       mmap_reuse,
+                       vdex_file->Fd(),
+                       vdex_length,
+                       vdex_filename,
+                       writable,
+                       low_4gb,
+                       unquicken,
+                       error_msg);
 }
 
-std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
-                                         size_t vdex_length,
-                                         const std::string& vdex_filename,
-                                         bool writable,
-                                         bool low_4gb,
-                                         bool unquicken,
-                                         std::string* error_msg) {
-  std::unique_ptr<MemMap> mmap(MemMap::MapFile(
+std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
+                                                  size_t mmap_size,
+                                                  bool mmap_reuse,
+                                                  int file_fd,
+                                                  size_t vdex_length,
+                                                  const std::string& vdex_filename,
+                                                  bool writable,
+                                                  bool low_4gb,
+                                                  bool unquicken,
+                                                  std::string* error_msg) {
+  if (mmap_addr != nullptr && mmap_size < vdex_length) {
+    LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex.";
+    mmap_addr = nullptr;
+    mmap_reuse = false;
+  }
+  CHECK(!mmap_reuse || mmap_addr != nullptr);
+  std::unique_ptr<MemMap> mmap(MemMap::MapFileAtAddress(
+      mmap_addr,
       vdex_length,
       (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
       unquicken ? MAP_PRIVATE : MAP_SHARED,
       file_fd,
       0 /* start offset */,
       low_4gb,
+      mmap_reuse,
       vdex_filename.c_str(),
       error_msg));
   if (mmap == nullptr) {
@@ -120,9 +145,8 @@
     if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
       return nullptr;
     }
-    Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
-              vdex->GetQuickeningInfo(),
-              /* decompile_return_instruction */ false);
+    vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
+                    /* decompile_return_instruction */ false);
     // Update the quickening info size to pretend there isn't any.
     reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
   }
@@ -135,19 +159,21 @@
   DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
   if (cursor == nullptr) {
     // Beginning of the iteration, return the first dex file if there is one.
-    return HasDexSection() ? DexBegin() : nullptr;
+    return HasDexSection() ? DexBegin() + sizeof(QuickeningTableOffsetType) : nullptr;
   } else {
     // Fetch the next dex file. Return null if there is none.
     const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
     // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
     // OatWriter::SeekToDexFiles.
     data = AlignUp(data, 4);
-    return (data == DexEnd()) ? nullptr : data;
+
+    return (data == DexEnd()) ? nullptr : data + sizeof(QuickeningTableOffsetType);
   }
 }
 
 bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
                                std::string* error_msg) {
+  const ArtDexFileLoader dex_file_loader;
   size_t i = 0;
   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
        dex_file_start != nullptr;
@@ -156,14 +182,14 @@
     // TODO: Supply the location information for a vdex file.
     static constexpr char kVdexLocation[] = "";
     std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
-    std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start,
-                                                           size,
-                                                           location,
-                                                           GetLocationChecksum(i),
-                                                           nullptr /*oat_dex_file*/,
-                                                           false /*verify*/,
-                                                           false /*verify_checksum*/,
-                                                           error_msg));
+    std::unique_ptr<const DexFile> dex(dex_file_loader.Open(dex_file_start,
+                                                            size,
+                                                            location,
+                                                            GetLocationChecksum(i),
+                                                            nullptr /*oat_dex_file*/,
+                                                            false /*verify*/,
+                                                            false /*verify_checksum*/,
+                                                            error_msg));
     if (dex == nullptr) {
       return false;
     }
@@ -172,64 +198,68 @@
   return true;
 }
 
-void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
-                         ArrayRef<const uint8_t> quickening_info,
-                         bool decompile_return_instruction) {
-  if (quickening_info.size() == 0 && !decompile_return_instruction) {
-    // Bail early if there is no quickening info and no need to decompile
-    // RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
-    return;
+void VdexFile::Unquicken(const std::vector<const DexFile*>& target_dex_files,
+                         bool decompile_return_instruction) const {
+  const uint8_t* source_dex = GetNextDexFileData(nullptr);
+  for (const DexFile* target_dex : target_dex_files) {
+    UnquickenDexFile(*target_dex, source_dex, decompile_return_instruction);
+    source_dex = GetNextDexFileData(source_dex);
   }
-
-  for (uint32_t i = 0; i < dex_files.size(); ++i) {
-    UnquickenDexFile(*dex_files[i], quickening_info, decompile_return_instruction);
-  }
+  DCHECK(source_dex == nullptr);
 }
 
-typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
-
-static uint32_t GetDebugInfoOffsetInternal(const DexFile& dex_file,
-                                           uint32_t offset_in_code_item,
-                                           const ArrayRef<const uint8_t>& quickening_info) {
-  if (quickening_info.size() == 0) {
-    // No quickening info: offset is the right one, return it.
-    return offset_in_code_item;
-  }
-  uint32_t quickening_offset = offset_in_code_item - dex_file.Size();
-  return *reinterpret_cast<const unaligned_uint32_t*>(quickening_info.data() + quickening_offset);
+uint32_t VdexFile::GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const {
+  DCHECK_GE(source_dex_begin, DexBegin());
+  DCHECK_LT(source_dex_begin, DexEnd());
+  return reinterpret_cast<const QuickeningTableOffsetType*>(source_dex_begin)[-1];
 }
 
-static uint32_t GetQuickeningInfoOffsetFrom(const DexFile& dex_file,
-                                            uint32_t offset_in_code_item,
-                                            const ArrayRef<const uint8_t>& quickening_info) {
-  if (offset_in_code_item < dex_file.Size()) {
-    return VdexFile::kNoQuickeningInfoOffset;
-  }
-  if (quickening_info.size() == 0) {
-    // No quickening info.
-    return VdexFile::kNoQuickeningInfoOffset;
-  }
-  uint32_t quickening_offset = offset_in_code_item - dex_file.Size();
+QuickenInfoOffsetTableAccessor VdexFile::GetQuickenInfoOffsetTable(
+    const uint8_t* source_dex_begin,
+    uint32_t num_method_ids,
+    const ArrayRef<const uint8_t>& quickening_info) const {
+  // The offset a is in preheader right before the dex file.
+  const uint32_t offset = GetQuickeningInfoTableOffset(source_dex_begin);
+  const uint8_t* data_ptr = quickening_info.data() + offset;
+  return QuickenInfoOffsetTableAccessor(data_ptr, num_method_ids);
+}
 
-  // Add 2 * sizeof(uint32_t) for the debug info offset and the data offset.
-  CHECK_LE(quickening_offset + 2 * sizeof(uint32_t), quickening_info.size());
-  return *reinterpret_cast<const unaligned_uint32_t*>(
-      quickening_info.data() + quickening_offset + sizeof(uint32_t));
+QuickenInfoOffsetTableAccessor VdexFile::GetQuickenInfoOffsetTable(
+    const DexFile& dex_file,
+    const ArrayRef<const uint8_t>& quickening_info) const {
+  return GetQuickenInfoOffsetTable(dex_file.Begin(), dex_file.NumMethodIds(), quickening_info);
 }
 
 static ArrayRef<const uint8_t> GetQuickeningInfoAt(const ArrayRef<const uint8_t>& quickening_info,
                                                    uint32_t quickening_offset) {
-  return (quickening_offset == VdexFile::kNoQuickeningInfoOffset)
-      ? ArrayRef<const uint8_t>(nullptr, 0)
-      : quickening_info.SubArray(
-            quickening_offset + sizeof(uint32_t),
-            *reinterpret_cast<const unaligned_uint32_t*>(
-                quickening_info.data() + quickening_offset));
+  ArrayRef<const uint8_t> remaining = quickening_info.SubArray(quickening_offset);
+  return remaining.SubArray(0u, QuickenInfoTable::SizeInBytes(remaining));
+}
+
+static uint32_t GetQuickeningInfoOffset(const QuickenInfoOffsetTableAccessor& table,
+                                        uint32_t dex_method_index,
+                                        const ArrayRef<const uint8_t>& quickening_info) {
+  DCHECK(!quickening_info.empty());
+  uint32_t remainder;
+  uint32_t offset = table.ElementOffset(dex_method_index, &remainder);
+  // Decode the sizes for the remainder offsets (not covered by the table).
+  while (remainder != 0) {
+    offset += GetQuickeningInfoAt(quickening_info, offset).size();
+    --remainder;
+  }
+  return offset;
 }
 
 void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
-                                ArrayRef<const uint8_t> quickening_info,
-                                bool decompile_return_instruction) {
+                                const DexFile& source_dex_file,
+                                bool decompile_return_instruction) const {
+  UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction);
+}
+
+void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
+                                const uint8_t* source_dex_begin,
+                                bool decompile_return_instruction) const {
+  ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
   if (quickening_info.size() == 0 && !decompile_return_instruction) {
     // Bail early if there is no quickening info and no need to decompile
     // RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
@@ -244,19 +274,20 @@
            class_it.Next()) {
         if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
           const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
-          uint32_t quickening_offset = GetQuickeningInfoOffsetFrom(
-              target_dex_file, code_item->debug_info_off_, quickening_info);
-          if (quickening_offset != VdexFile::kNoQuickeningInfoOffset) {
-            // If we have quickening data, put back the original debug_info_off.
-            const_cast<DexFile::CodeItem*>(code_item)->SetDebugInfoOffset(
-                GetDebugInfoOffsetInternal(target_dex_file,
-                                           code_item->debug_info_off_,
-                                           quickening_info));
+          ArrayRef<const uint8_t> quicken_data;
+          if (!quickening_info.empty()) {
+            const uint32_t quickening_offset = GetQuickeningInfoOffset(
+                GetQuickenInfoOffsetTable(source_dex_begin,
+                                          target_dex_file.NumMethodIds(),
+                                          quickening_info),
+                class_it.GetMemberIndex(),
+                quickening_info);
+            quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset);
           }
           optimizer::ArtDecompileDEX(
               target_dex_file,
               *code_item,
-              GetQuickeningInfoAt(quickening_info, quickening_offset),
+              quicken_data,
               decompile_return_instruction);
         }
       }
@@ -264,25 +295,17 @@
   }
 }
 
-uint32_t VdexFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const {
-  return GetDebugInfoOffsetInternal(dex_file, offset_in_code_item, GetQuickeningInfo());
-}
-
-const uint8_t* VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
-                                            uint32_t code_item_offset) const {
+ArrayRef<const uint8_t> VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
+                                                     uint32_t dex_method_idx) const {
   ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
-  uint32_t quickening_offset = GetQuickeningInfoOffsetFrom(
-      dex_file, dex_file.GetCodeItem(code_item_offset)->debug_info_off_, quickening_info);
-
-  return GetQuickeningInfoAt(quickening_info, quickening_offset).data();
-}
-
-bool VdexFile::CanEncodeQuickenedData(const DexFile& dex_file) {
-  // We are going to use the debug_info_off_ to signal there is
-  // quickened data, by putting a value greater than dex_file.Size(). So
-  // make sure we have some room in the offset by checking that we have at least
-  // half of the range of a uint32_t.
-  return dex_file.Size() <= (std::numeric_limits<uint32_t>::max() >> 1);
+  if (quickening_info.empty()) {
+    return ArrayRef<const uint8_t>();
+  }
+  const uint32_t quickening_offset = GetQuickeningInfoOffset(
+      GetQuickenInfoOffsetTable(dex_file, quickening_info),
+      dex_method_idx,
+      quickening_info);
+  return GetQuickeningInfoAt(quickening_info, quickening_offset);
 }
 
 }  // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 2d9fcab..4687a39 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -24,6 +24,7 @@
 #include "base/macros.h"
 #include "mem_map.h"
 #include "os.h"
+#include "quicken_info.h"
 
 namespace art {
 
@@ -35,18 +36,17 @@
 // File format:
 //   VdexFile::Header    fixed-length header
 //
-//   DEX[0]              array of the input DEX files
-//   DEX[1]              the bytecode may have been quickened
+//   quicken_table_off[0]  offset into QuickeningInfo section for offset table for DEX[0].
+//   DEX[0]                array of the input DEX files, the bytecode may have been quickened.
+//   quicken_table_off[1]
+//   DEX[1]
 //   ...
 //   DEX[D]
 //   VerifierDeps
 //      uint8[D][]                 verification dependencies
 //   QuickeningInfo
 //     uint8[D][]                  quickening data
-//     unaligned_uint32_t[D][2][]  table of offsets pair:
-//                                   uint32_t[0] contains original CodeItem::debug_info_off_
-//                                   uint32_t[1] contains quickening data offset from the start
-//                                                of QuickeningInfo
+//     uint32[D][]                 quickening data offset tables
 
 class VdexFile {
  public:
@@ -84,8 +84,8 @@
 
    private:
     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
-    // Last update: Lookup-friendly encoding for quickening info.
-    static constexpr uint8_t kVdexVersion[] = { '0', '1', '1', '\0' };
+    // Last update: Side table for debug info offsets in compact dex.
+    static constexpr uint8_t kVdexVersion[] = { '0', '1', '4', '\0' };
 
     uint8_t magic_[4];
     uint8_t version_[4];
@@ -98,15 +98,49 @@
   };
 
   typedef uint32_t VdexChecksum;
+  using QuickeningTableOffsetType = uint32_t;
 
   explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
 
   // Returns nullptr if the vdex file cannot be opened or is not valid.
+  // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
+  static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
+                                                 size_t mmap_size,
+                                                 bool mmap_reuse,
+                                                 const std::string& vdex_filename,
+                                                 bool writable,
+                                                 bool low_4gb,
+                                                 bool unquicken,
+                                                 std::string* error_msg);
+
+  // Returns nullptr if the vdex file cannot be opened or is not valid.
+  // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
+  static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
+                                                 size_t mmap_size,
+                                                 bool mmap_reuse,
+                                                 int file_fd,
+                                                 size_t vdex_length,
+                                                 const std::string& vdex_filename,
+                                                 bool writable,
+                                                 bool low_4gb,
+                                                 bool unquicken,
+                                                 std::string* error_msg);
+
+  // Returns nullptr if the vdex file cannot be opened or is not valid.
   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
                                         bool writable,
                                         bool low_4gb,
                                         bool unquicken,
-                                        std::string* error_msg);
+                                        std::string* error_msg) {
+    return OpenAtAddress(nullptr,
+                         0,
+                         false,
+                         vdex_filename,
+                         writable,
+                         low_4gb,
+                         unquicken,
+                         error_msg);
+  }
 
   // Returns nullptr if the vdex file cannot be opened or is not valid.
   static std::unique_ptr<VdexFile> Open(int file_fd,
@@ -115,7 +149,18 @@
                                         bool writable,
                                         bool low_4gb,
                                         bool unquicken,
-                                        std::string* error_msg);
+                                        std::string* error_msg) {
+    return OpenAtAddress(nullptr,
+                         0,
+                         false,
+                         file_fd,
+                         vdex_length,
+                         vdex_filename,
+                         writable,
+                         low_4gb,
+                         unquicken,
+                         error_msg);
+  }
 
   const uint8_t* Begin() const { return mmap_->Begin(); }
   const uint8_t* End() const { return mmap_->End(); }
@@ -160,29 +205,42 @@
   // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
   // decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator
   // instead of the faster QuickeningInfoIterator.
-  static void Unquicken(const std::vector<const DexFile*>& dex_files,
-                        ArrayRef<const uint8_t> quickening_info,
-                        bool decompile_return_instruction);
+  // Always unquickens using the vdex dex files as the source for quicken tables.
+  void Unquicken(const std::vector<const DexFile*>& target_dex_files,
+                 bool decompile_return_instruction) const;
 
   // Fully unquicken `target_dex_file` based on `quickening_info`.
-  static void UnquickenDexFile(const DexFile& target_dex_file,
-                               ArrayRef<const uint8_t> quickening_info,
-                               bool decompile_return_instruction);
+  void UnquickenDexFile(const DexFile& target_dex_file,
+                        const DexFile& source_dex_file,
+                        bool decompile_return_instruction) const;
 
-  // Return the quickening info of the given code item.
-  const uint8_t* GetQuickenedInfoOf(const DexFile& dex_file, uint32_t code_item_offset) const;
-
-  uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const;
-
-  static bool CanEncodeQuickenedData(const DexFile& dex_file);
-
-  static constexpr uint32_t kNoQuickeningInfoOffset = -1;
+  // Return the quickening info of a given method index (or null if it's empty).
+  ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
+                                             uint32_t dex_method_idx) const;
 
  private:
+  uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
+
+  // Source dex must be the in the vdex file.
+  void UnquickenDexFile(const DexFile& target_dex_file,
+                        const uint8_t* source_dex_begin,
+                        bool decompile_return_instruction) const;
+
+  QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable(
+        const DexFile& dex_file,
+        const ArrayRef<const uint8_t>& quickening_info) const;
+
+  QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable(
+      const uint8_t* source_dex_begin,
+      uint32_t num_method_ids,
+      const ArrayRef<const uint8_t>& quickening_info) const;
+
   bool HasDexSection() const {
     return GetHeader().GetDexSize() != 0;
   }
 
+  bool ContainsDexFile(const DexFile& dex_file) const;
+
   const uint8_t* DexBegin() const {
     return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection();
   }
@@ -191,8 +249,6 @@
     return DexBegin() + GetHeader().GetDexSize();
   }
 
-  uint32_t GetDexFileIndex(const DexFile& dex_file) const;
-
   std::unique_ptr<MemMap> mmap_;
 
   DISALLOW_COPY_AND_ASSIGN(VdexFile);
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/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index e9cb35e..c076d15 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -28,6 +28,7 @@
 #include "base/macros.h"
 #include "bytecode_utils.h"
 #include "dex/code_item_accessors-inl.h"
+#include "dex/art_dex_file_loader.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_instruction.h"
@@ -66,15 +67,16 @@
   if (IsJVM()) {
     return;
   }
+  const ArtDexFileLoader dex_file_loader;
   std::string error;
-  std::unique_ptr<const DexFile> dex(DexFileLoader::Open(class_data,
-                                                         class_data_len,
-                                                         "fake_location.dex",
-                                                         /*location_checksum*/ 0,
-                                                         /*oat_dex_file*/ nullptr,
-                                                         /*verify*/ true,
-                                                         /*verify_checksum*/ true,
-                                                         &error));
+  std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data,
+                                                          class_data_len,
+                                                          "fake_location.dex",
+                                                          /*location_checksum*/ 0,
+                                                          /*oat_dex_file*/ nullptr,
+                                                          /*verify*/ true,
+                                                          /*verify_checksum*/ true,
+                                                          &error));
   if (dex.get() == nullptr) {
     std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
     return;
diff --git a/test/knownfailures.json b/test/knownfailures.json
index a12510c..9db8e9d 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -442,6 +442,7 @@
             "957-methodhandle-transforms",
             "958-methodhandle-stackframe",
             "959-invoke-polymorphic-accessors",
+            "979-const-method-handle",
             "990-method-handle-and-mr"
         ],
         "description": [
@@ -647,7 +648,7 @@
     },
     {
         "tests": "661-oat-writer-layout",
-        "variant": "interp-ac | interpreter | jit | no-dex2oat | no-prebuild | no-image | trace",
+        "variant": "interp-ac | interpreter | jit | no-dex2oat | no-prebuild | no-image | trace | redefine-stress | jvmti-stress",
         "description": ["Test is designed to only check --compiler-filter=speed"]
     }
 
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 297ce08..2bb407d 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -234,8 +234,8 @@
         'env' : {
             'ART_USE_READ_BARRIER' : 'false',
             'ART_HEAP_POISONING' : 'true',
-            # Get some extra automated testing coverage for compact dex.
-            'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'fast'
+            # Disable compact dex to get coverage of standard dex file usage.
+            'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'none'
         }
     },
     'art-preopt' : {
@@ -280,8 +280,8 @@
         'env': {
             'ART_DEFAULT_GC_TYPE' : 'SS',
             'ART_USE_READ_BARRIER' : 'false',
-            # Get some extra automated testing coverage for compact dex.
-            'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'fast'
+            # Disable compact dex to get coverage of standard dex file usage.
+            'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'none'
         }
     },
     'art-gtest-gss-gc': {