Merge "Remove unused build code"
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 3ce786e..c902d28 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -90,7 +90,7 @@
 
   // Compiles a virtual method invocation into a quick virtual method invocation.
   // The method index is replaced by the vtable index where the corresponding
-  // AbstractMethod can be found. Therefore, this does not involve any resolution
+  // Executable can be found. Therefore, this does not involve any resolution
   // at runtime.
   // Since the method index is encoded with 16 bits, we can replace it only if the
   // vtable index can be encoded with 16 bits too.
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 6d86f7d..cdb57a9 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -48,12 +48,12 @@
 #include "intern_table.h"
 #include "linear_alloc.h"
 #include "lock_word.h"
-#include "mirror/abstract_method.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache.h"
 #include "mirror/dex_cache-inl.h"
+#include "mirror/executable.h"
 #include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
@@ -1989,14 +1989,10 @@
   } else {
     if (klass == mirror::Method::StaticClass() || klass == mirror::Constructor::StaticClass()) {
       // Need to go update the ArtMethod.
-      auto* dest = down_cast<mirror::AbstractMethod*>(copy);
-      auto* src = down_cast<mirror::AbstractMethod*>(orig);
+      auto* dest = down_cast<mirror::Executable*>(copy);
+      auto* src = down_cast<mirror::Executable*>(orig);
       ArtMethod* src_method = src->GetArtMethod();
-      auto it = native_object_relocations_.find(src_method);
-      CHECK(it != native_object_relocations_.end())
-          << "Missing relocation for AbstractMethod.artMethod " << PrettyMethod(src_method);
-      dest->SetArtMethod(
-          reinterpret_cast<ArtMethod*>(global_image_begin_ + it->second.offset));
+      dest->SetArtMethod(GetImageMethodAddress(src_method));
     } else if (!klass->IsArrayClass()) {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       if (klass == class_linker->GetClassRoot(ClassLinker::kJavaLangDexCache)) {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index d629c0c..9045817 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -55,6 +55,7 @@
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "vdex_file.h"
 #include "verifier/method_verifier.h"
+#include "verifier/verifier_deps.h"
 #include "zip_archive.h"
 
 namespace art {
@@ -297,6 +298,7 @@
     dex_files_(nullptr),
     vdex_size_(0u),
     vdex_dex_files_offset_(0u),
+    vdex_verifier_deps_offset_(0u),
     oat_size_(0u),
     bss_size_(0u),
     oat_data_offset_(0u),
@@ -307,6 +309,8 @@
     size_oat_header_(0),
     size_oat_header_key_value_store_(0),
     size_dex_file_(0),
+    size_verifier_deps_(0),
+    size_verifier_deps_alignment_(0),
     size_interpreter_to_interpreter_bridge_(0),
     size_interpreter_to_compiled_code_bridge_(0),
     size_jni_dlsym_lookup_(0),
@@ -476,11 +480,6 @@
         !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
       return false;
     }
-
-    // VDEX is finalized. Seek to the beginning of the file and write the header.
-    if (!WriteVdexHeader(vdex_out.get())) {
-      return false;
-    }
   } else {
     // Write DEX files into OAT, mmap and open them.
     if (!WriteDexFiles(oat_rodata, vdex_file) ||
@@ -1595,6 +1594,52 @@
   return true;
 }
 
+bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
+  if (!kIsVdexEnabled) {
+    return true;
+  }
+
+  if (verifier_deps == nullptr) {
+    // Nothing to write. Record the offset, but no need
+    // for alignment.
+    vdex_verifier_deps_offset_ = vdex_size_;
+    return true;
+  }
+
+  size_t initial_offset = vdex_size_;
+  size_t start_offset = RoundUp(initial_offset, 4u);
+
+  vdex_size_ = start_offset;
+  vdex_verifier_deps_offset_ = vdex_size_;
+  size_verifier_deps_alignment_ = start_offset - initial_offset;
+
+  off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
+  if (actual_offset != static_cast<off_t>(start_offset)) {
+    PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
+                << " Expected: " << start_offset
+                << " Output: " << vdex_out->GetLocation();
+    return false;
+  }
+
+  std::vector<uint8_t> buffer;
+  verifier_deps->Encode(&buffer);
+
+  if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
+    PLOG(ERROR) << "Failed to write verifier deps."
+                << " File: " << vdex_out->GetLocation();
+    return false;
+  }
+  if (!vdex_out->Flush()) {
+    PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
+                << " File: " << vdex_out->GetLocation();
+    return false;
+  }
+
+  size_verifier_deps_ = buffer.size();
+  vdex_size_ += size_verifier_deps_;
+  return true;
+}
+
 bool OatWriter::WriteCode(OutputStream* out) {
   CHECK(write_state_ == WriteState::kWriteText);
 
@@ -1638,6 +1683,8 @@
     DO_STAT(size_oat_header_);
     DO_STAT(size_oat_header_key_value_store_);
     DO_STAT(size_dex_file_);
+    DO_STAT(size_verifier_deps_);
+    DO_STAT(size_verifier_deps_alignment_);
     DO_STAT(size_interpreter_to_interpreter_bridge_);
     DO_STAT(size_interpreter_to_compiled_code_bridge_);
     DO_STAT(size_jni_dlsym_lookup_);
@@ -2341,6 +2388,9 @@
 }
 
 bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) {
+  if (!kIsVdexEnabled) {
+    return true;
+  }
   off_t actual_offset = vdex_out->Seek(0, kSeekSet);
   if (actual_offset != 0) {
     PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
@@ -2348,12 +2398,24 @@
     return false;
   }
 
-  VdexFile::Header vdex_header;
+  DCHECK_NE(vdex_dex_files_offset_, 0u);
+  DCHECK_NE(vdex_verifier_deps_offset_, 0u);
+
+  size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
+  size_t verifier_deps_section_size = vdex_size_ - vdex_verifier_deps_offset_;
+
+  VdexFile::Header vdex_header(dex_section_size, verifier_deps_section_size);
   if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
     PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
     return false;
   }
 
+  if (!vdex_out->Flush()) {
+    PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
+                << " File: " << vdex_out->GetLocation();
+    return false;
+  }
+
   return true;
 }
 
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index dd7d699..670accb 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -50,6 +50,10 @@
 class MultiOatRelativePatcher;
 }  // namespace linker
 
+namespace verifier {
+  class VerifierDeps;
+}  // namespace verifier
+
 // OatHeader         variable length with count of D OatDexFiles
 //
 // OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
@@ -149,6 +153,9 @@
                             bool verify,
                             /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
                             /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
+  bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps);
+  bool WriteVdexHeader(OutputStream* vdex_out);
+
   // Prepare layout of remaining data.
   void PrepareLayout(const CompilerDriver* compiler,
                      ImageWriter* image_writer,
@@ -232,8 +239,6 @@
   // with a given DexMethodVisitor.
   bool VisitDexMethods(DexMethodVisitor* visitor);
 
-  bool WriteVdexHeader(OutputStream* vdex_out);
-
   bool WriteDexFiles(OutputStream* out, File* file);
   bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
   bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
@@ -311,6 +316,9 @@
   // Offset of section holding Dex files inside Vdex.
   size_t vdex_dex_files_offset_;
 
+  // Offset of section holding VerifierDeps inside Vdex.
+  size_t vdex_verifier_deps_offset_;
+
   // Size required for Oat data structures.
   size_t oat_size_;
 
@@ -341,6 +349,8 @@
   uint32_t size_oat_header_;
   uint32_t size_oat_header_key_value_store_;
   uint32_t size_dex_file_;
+  uint32_t size_verifier_deps_;
+  uint32_t size_verifier_deps_alignment_;
   uint32_t size_interpreter_to_interpreter_bridge_;
   uint32_t size_interpreter_to_compiled_code_bridge_;
   uint32_t size_jni_dlsym_lookup_;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 51ba187..137cd21 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1117,7 +1117,8 @@
   }
 }
 
-LocationSummary* CodeGenerator::CreateNullCheckLocations(HNullCheck* null_check) {
+LocationSummary* CodeGenerator::CreateThrowingSlowPathLocations(HInstruction* instruction,
+                                                                RegisterSet caller_saves) {
   // Note: Using kNoCall allows the method to be treated as leaf (and eliminate the
   // HSuspendCheck from entry block). However, it will still get a valid stack frame
   // because the HNullCheck needs an environment.
@@ -1125,16 +1126,15 @@
   // When throwing from a try block, we may need to retrieve dalvik registers from
   // physical registers and we also need to set up stack mask for GC. This is
   // implicitly achieved by passing kCallOnSlowPath to the LocationSummary.
-  bool can_throw_into_catch_block = null_check->CanThrowIntoCatchBlock();
+  bool can_throw_into_catch_block = instruction->CanThrowIntoCatchBlock();
   if (can_throw_into_catch_block) {
     call_kind = LocationSummary::kCallOnSlowPath;
   }
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(null_check, call_kind);
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   if (can_throw_into_catch_block && compiler_options_.GetImplicitNullChecks()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(caller_saves);  // Default: no caller-save registers.
   }
-  locations->SetInAt(0, Location::RequiresRegister());
-  DCHECK(!null_check->HasUses());
+  DCHECK(!instruction->HasUses());
   return locations;
 }
 
@@ -1273,7 +1273,7 @@
   }
 
   const uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
-  for (size_t i : LowToHighBits(fp_spills)) {
+  for (uint32_t i : LowToHighBits(fp_spills)) {
     DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
     saved_fpu_stack_offsets_[i] = stack_offset;
@@ -1292,7 +1292,7 @@
   }
 
   const uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
-  for (size_t i : LowToHighBits(fp_spills)) {
+  for (uint32_t i : LowToHighBits(fp_spills)) {
     DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
     stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, i);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 22b5c9c..c0c798d 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -313,7 +313,8 @@
 
   bool CanMoveNullCheckToUser(HNullCheck* null_check);
   void MaybeRecordImplicitNullCheck(HInstruction* instruction);
-  LocationSummary* CreateNullCheckLocations(HNullCheck* null_check);
+  LocationSummary* CreateThrowingSlowPathLocations(
+      HInstruction* instruction, RegisterSet caller_saves = RegisterSet::Empty());
   void GenerateNullCheck(HNullCheck* null_check);
   virtual void GenerateImplicitNullCheck(HNullCheck* null_check) = 0;
   virtual void GenerateExplicitNullCheck(HNullCheck* null_check) = 0;
@@ -579,6 +580,7 @@
         core_spill_mask_(0),
         fpu_spill_mask_(0),
         first_register_slot_in_slow_path_(0),
+        allocated_registers_(RegisterSet::Empty()),
         blocked_core_registers_(graph->GetArena()->AllocArray<bool>(number_of_core_registers,
                                                                     kArenaAllocCodeGenerator)),
         blocked_fpu_registers_(graph->GetArena()->AllocArray<bool>(number_of_fpu_registers,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3b2758b..a052873 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -191,7 +191,7 @@
 
   uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
   orig_offset = stack_offset;
-  for (size_t i : LowToHighBits(fp_spills)) {
+  for (uint32_t i : LowToHighBits(fp_spills)) {
     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
     saved_fpu_stack_offsets_[i] = stack_offset;
     stack_offset += kArmWordSize;
@@ -275,10 +275,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -1681,7 +1677,7 @@
 void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -3264,14 +3260,8 @@
 }
 
 void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -4110,7 +4100,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
 
@@ -4430,7 +4420,8 @@
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
-  codegen_->CreateNullCheckLocations(instruction);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
 }
 
 void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -4582,7 +4573,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -5067,15 +5058,13 @@
 }
 
 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -5119,7 +5108,7 @@
 void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
@@ -5441,7 +5430,7 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
 
   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
@@ -5745,7 +5734,7 @@
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 7f542da..a29e9f3 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -139,18 +139,18 @@
 
 // Calculate memory accessing operand for save/restore live registers.
 static void SaveRestoreLiveRegistersHelper(CodeGenerator* codegen,
-                                           RegisterSet* register_set,
+                                           LocationSummary* locations,
                                            int64_t spill_offset,
                                            bool is_save) {
-  DCHECK(ArtVixlRegCodeCoherentForRegSet(register_set->GetCoreRegisters(),
+  const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
+  const uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(core_spills,
                                          codegen->GetNumberOfCoreRegisters(),
-                                         register_set->GetFloatingPointRegisters(),
+                                         fp_spills,
                                          codegen->GetNumberOfFloatingPointRegisters()));
 
-  CPURegList core_list = CPURegList(CPURegister::kRegister, kXRegSize,
-      register_set->GetCoreRegisters() & (~callee_saved_core_registers.GetList()));
-  CPURegList fp_list = CPURegList(CPURegister::kFPRegister, kDRegSize,
-      register_set->GetFloatingPointRegisters() & (~callee_saved_fp_registers.GetList()));
+  CPURegList core_list = CPURegList(CPURegister::kRegister, kXRegSize, core_spills);
+  CPURegList fp_list = CPURegList(CPURegister::kFPRegister, kDRegSize, fp_spills);
 
   MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler();
   UseScratchRegisterScope temps(masm);
@@ -184,38 +184,35 @@
 }
 
 void SlowPathCodeARM64::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
-  RegisterSet* register_set = locations->GetLiveRegisters();
   size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
-  for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
-    if (!codegen->IsCoreCalleeSaveRegister(i) && register_set->ContainsCoreRegister(i)) {
-      // If the register holds an object, update the stack mask.
-      if (locations->RegisterContainsObject(i)) {
-        locations->SetStackBit(stack_offset / kVRegSize);
-      }
-      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
-      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
-      saved_core_stack_offsets_[i] = stack_offset;
-      stack_offset += kXRegSizeInBytes;
+  const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
+  for (uint32_t i : LowToHighBits(core_spills)) {
+    // If the register holds an object, update the stack mask.
+    if (locations->RegisterContainsObject(i)) {
+      locations->SetStackBit(stack_offset / kVRegSize);
     }
+    DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+    DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+    saved_core_stack_offsets_[i] = stack_offset;
+    stack_offset += kXRegSizeInBytes;
   }
 
-  for (size_t i = 0, e = codegen->GetNumberOfFloatingPointRegisters(); i < e; ++i) {
-    if (!codegen->IsFloatingPointCalleeSaveRegister(i) &&
-        register_set->ContainsFloatingPointRegister(i)) {
-      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
-      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
-      saved_fpu_stack_offsets_[i] = stack_offset;
-      stack_offset += kDRegSizeInBytes;
-    }
+  const uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
+  for (uint32_t i : LowToHighBits(fp_spills)) {
+    DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+    DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+    saved_fpu_stack_offsets_[i] = stack_offset;
+    stack_offset += kDRegSizeInBytes;
   }
 
-  SaveRestoreLiveRegistersHelper(codegen, register_set,
+  SaveRestoreLiveRegistersHelper(codegen,
+                                 locations,
                                  codegen->GetFirstRegisterSlotInSlowPath(), true /* is_save */);
 }
 
 void SlowPathCodeARM64::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
-  RegisterSet* register_set = locations->GetLiveRegisters();
-  SaveRestoreLiveRegistersHelper(codegen, register_set,
+  SaveRestoreLiveRegistersHelper(codegen,
+                                 locations,
                                  codegen->GetFirstRegisterSlotInSlowPath(), false /* is_save */);
 }
 
@@ -261,10 +258,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     arm64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -1608,7 +1601,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   if (Primitive::IsFloatingPointType(instruction->GetType())) {
@@ -2036,7 +2029,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -2306,15 +2299,13 @@
 }
 
 void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1).GetCode()));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -2685,14 +2676,8 @@
 }
 
 void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -2924,7 +2909,7 @@
 void LocationsBuilderARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -3077,7 +3062,7 @@
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
@@ -3944,7 +3929,7 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
 
   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
@@ -4384,7 +4369,8 @@
 }
 
 void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
-  codegen_->CreateNullCheckLocations(instruction);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
 }
 
 void CodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -4670,7 +4656,7 @@
 void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index b2e7595..2211ea3 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -194,10 +194,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -2141,15 +2137,13 @@
 }
 
 void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -2664,14 +2658,8 @@
 }
 
 void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -3725,7 +3713,7 @@
 void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -5112,7 +5100,8 @@
 }
 
 void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
-  codegen_->CreateNullCheckLocations(instruction);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
 }
 
 void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -5406,7 +5395,7 @@
 void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 557e5da..5039fad 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -150,10 +150,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     mips64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -1558,15 +1554,13 @@
 }
 
 void LocationsBuilderMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -2110,14 +2104,8 @@
 }
 
 void LocationsBuilderMIPS64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorMIPS64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -2630,7 +2618,7 @@
 void LocationsBuilderMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -3461,7 +3449,8 @@
 }
 
 void LocationsBuilderMIPS64::VisitNullCheck(HNullCheck* instruction) {
-  codegen_->CreateNullCheckLocations(instruction);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
 }
 
 void CodeGeneratorMIPS64::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -3741,7 +3730,7 @@
 void LocationsBuilderMIPS64::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorMIPS64::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 172ce4a..cc9fe83 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -84,10 +84,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     x86_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -1458,7 +1454,7 @@
 void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::Any());
   }
@@ -3548,10 +3544,7 @@
 }
 
 void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   switch (instruction->GetType()) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
@@ -3571,9 +3564,6 @@
     default:
       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
   }
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -4517,7 +4507,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
 
@@ -4927,11 +4917,11 @@
 }
 
 void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary* locations = codegen_->CreateNullCheckLocations(instruction);
-  if (!codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
-    // Explicit null checks can use any location.
-    locations->SetInAt(0, Location::Any());
-  }
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
+      ? Location::RequiresRegister()
+      : Location::Any();
+  locations->SetInAt(0, loc);
 }
 
 void CodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -4978,7 +4968,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -5369,18 +5359,16 @@
 }
 
 void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
   HInstruction* length = instruction->InputAt(1);
   if (!length->IsEmittedAtUseSite()) {
     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   }
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -5444,7 +5432,7 @@
 void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
@@ -5802,7 +5790,7 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
 
   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
@@ -6099,7 +6087,7 @@
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 1943ddc..1d87bf6 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -88,10 +88,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
     __ Bind(GetEntryLabel());
-    if (instruction_->CanThrowIntoCatchBlock()) {
-      // Live registers will be restored in the catch block if caught.
-      SaveLiveRegisters(codegen, instruction_->GetLocations());
-    }
     x86_64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
@@ -1498,7 +1494,7 @@
 void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::Any());
   }
@@ -3618,14 +3614,8 @@
 }
 
 void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
   locations->SetInAt(0, Location::Any());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
@@ -4021,7 +4011,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   if (Primitive::IsFloatingPointType(instruction->GetType())) {
@@ -4396,11 +4386,11 @@
 }
 
 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary* locations = codegen_->CreateNullCheckLocations(instruction);
-  if (!codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
-    // Explicit null checks can use any location.
-    locations->SetInAt(0, Location::Any());
-  }
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
+  Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
+      ? Location::RequiresRegister()
+      : Location::Any();
+  locations->SetInAt(0, loc);
 }
 
 void CodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -4447,7 +4437,7 @@
                                                        LocationSummary::kCallOnSlowPath :
                                                        LocationSummary::kNoCall);
   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -4818,18 +4808,16 @@
 }
 
 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  RegisterSet caller_saves = RegisterSet::Empty();
+  InvokeRuntimeCallingConvention calling_convention;
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
   HInstruction* length = instruction->InputAt(1);
   if (!length->IsEmittedAtUseSite()) {
     locations->SetInAt(1, Location::RegisterOrConstant(length));
   }
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
 }
 
 void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -4912,7 +4900,7 @@
 void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
-  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
 }
 
 void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
@@ -5213,7 +5201,7 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
 
   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
@@ -5488,7 +5476,7 @@
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index eda0971..776a483 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -273,9 +273,9 @@
 // only SP/WSP and ZXR/WZR codes are different between art and vixl.
 // Note: This function is only used for debug checks.
 inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
-                                                   size_t num_core,
-                                                   uint32_t art_fpu_registers,
-                                                   size_t num_fpu) {
+                                            size_t num_core,
+                                            uint32_t art_fpu_registers,
+                                            size_t num_fpu) {
   // The register masks won't work if the number of register is larger than 32.
   DCHECK_GE(sizeof(art_core_registers) * 8, num_core);
   DCHECK_GE(sizeof(art_fpu_registers) * 8, num_fpu);
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 67640a1..fd2da10 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -657,7 +657,7 @@
                                                                LocationSummary::kNoCall,
                                                            kIntrinsified);
   if (can_call && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   locations->SetInAt(1, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 082076d..ce58657 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -895,7 +895,7 @@
                                                                LocationSummary::kNoCall,
                                                            kIntrinsified);
   if (can_call && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   locations->SetInAt(1, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index d17f85e..e61aba0 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1977,7 +1977,7 @@
                                                                LocationSummary::kNoCall,
                                                            kIntrinsified);
   if (can_call && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   locations->SetInAt(1, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index f8f30d9..0f31fab 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2110,7 +2110,7 @@
                                                                LocationSummary::kNoCall,
                                                            kIntrinsified);
   if (can_call && kUseBakerReadBarrier) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   }
   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   locations->SetInAt(1, Location::RequiresRegister());
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 1b1b3a7..d157509 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -33,8 +33,8 @@
       output_overlaps_(Location::kOutputOverlap),
       stack_mask_(nullptr),
       register_mask_(0),
-      live_registers_(),
-      custom_slow_path_caller_saves_() {
+      live_registers_(RegisterSet::Empty()),
+      custom_slow_path_caller_saves_(RegisterSet::Empty()) {
   instruction->SetLocations(this);
 
   if (NeedsSafepoint()) {
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index c97c4a6..da27928 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -420,7 +420,7 @@
 
 class RegisterSet : public ValueObject {
  public:
-  RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
+  static RegisterSet Empty() { return RegisterSet(); }
 
   void Add(Location loc) {
     if (loc.IsRegister()) {
@@ -465,6 +465,8 @@
   }
 
  private:
+  RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
+
   uint32_t core_registers_;
   uint32_t floating_point_registers_;
 };
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d99d2d6..245653d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -64,6 +64,8 @@
 #include "interpreter/unstarted_runtime.h"
 #include "jit/offline_profiling_info.h"
 #include "leb128.h"
+#include "linker/buffered_output_stream.h"
+#include "linker/file_output_stream.h"
 #include "linker/multi_oat_relative_patcher.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -1753,6 +1755,28 @@
       }
     }
 
+    {
+      TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_);
+      DCHECK(IsBootImage() || oat_files_.size() == 1u);
+      DCHECK_EQ(IsBootImage(), verifier_deps_ == nullptr);
+      for (size_t i = 0, size = oat_files_.size(); i != size; ++i) {
+        File* vdex_file = vdex_files_[i].get();
+        std::unique_ptr<BufferedOutputStream> vdex_out(
+            MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(vdex_file)));
+
+        if (!oat_writers_[i]->WriteVerifierDeps(vdex_out.get(), verifier_deps_.get())) {
+          LOG(ERROR) << "Failed to write verifier dependencies into VDEX " << vdex_file->GetPath();
+          return false;
+        }
+
+        // VDEX finalized, seek back to the beginning and write the header.
+        if (!oat_writers_[i]->WriteVdexHeader(vdex_out.get())) {
+          LOG(ERROR) << "Failed to write vdex header into VDEX " << vdex_file->GetPath();
+          return false;
+        }
+      }
+    }
+
     linker::MultiOatRelativePatcher patcher(instruction_set_, instruction_set_features_.get());
     {
       TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_);
@@ -2604,6 +2628,7 @@
   std::vector<std::unique_ptr<ElfWriter>> elf_writers_;
   std::vector<std::unique_ptr<OatWriter>> oat_writers_;
   std::vector<OutputStream*> rodata_;
+  std::vector<std::unique_ptr<OutputStream>> vdex_out_;
   std::unique_ptr<ImageWriter> image_writer_;
   std::unique_ptr<CompilerDriver> driver_;
 
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 163cb01..c411572 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -18,6 +18,7 @@
     srcs: [
         "dexlayout_main.cc",
         "dexlayout.cc",
+        "dex_ir.cc",
         "dex_ir_builder.cc",
     ],
     cflags: ["-Wall"],
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
new file mode 100644
index 0000000..aff03cd
--- /dev/null
+++ b/dexlayout/dex_ir.cc
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ * Implementation file of the dexlayout utility.
+ *
+ * This is a tool to read dex files into an internal representation,
+ * reorganize the representation, and emit dex files with a better
+ * file layout.
+ */
+
+#include "dex_ir.h"
+#include "dex_ir_builder.h"
+
+namespace art {
+namespace dex_ir {
+
+static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
+  uint64_t value = 0;
+  for (uint32_t i = 0; i <= length; i++) {
+    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
+  }
+  if (sign_extend) {
+    int shift = (7 - length) * 8;
+    return (static_cast<int64_t>(value) << shift) >> shift;
+  }
+  return value;
+}
+
+static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
+  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
+  PositionInfoVector& positions = debug_info->GetPositionInfo();
+  positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
+  return false;
+}
+
+static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
+  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
+  LocalInfoVector& locals = debug_info->GetLocalInfo();
+  const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
+  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
+  locals.push_back(std::unique_ptr<LocalInfo>(
+      new LocalInfo(name, entry.descriptor_, signature, entry.start_address_,
+                    entry.end_address_, entry.reg_)));
+}
+
+EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) {
+  const uint8_t encoded_value = *(*data)++;
+  const uint8_t type = encoded_value & 0x1f;
+  EncodedValue* item = new EncodedValue(type);
+  ReadEncodedValue(data, type, encoded_value >> 5, item);
+  return item;
+}
+
+EncodedValue* Collections::ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length) {
+  EncodedValue* item = new EncodedValue(type);
+  ReadEncodedValue(data, type, length, item);
+  return item;
+}
+
+void Collections::ReadEncodedValue(
+    const uint8_t** data, uint8_t type, uint8_t length, EncodedValue* item) {
+  switch (type) {
+    case DexFile::kDexAnnotationByte:
+      item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
+      break;
+    case DexFile::kDexAnnotationShort:
+      item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationChar:
+      item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
+      break;
+    case DexFile::kDexAnnotationInt:
+      item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationLong:
+      item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
+      break;
+    case DexFile::kDexAnnotationFloat: {
+      // Fill on right.
+      union {
+        float f;
+        uint32_t data;
+      } conv;
+      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
+      item->SetFloat(conv.f);
+      break;
+    }
+    case DexFile::kDexAnnotationDouble: {
+      // Fill on right.
+      union {
+        double d;
+        uint64_t data;
+      } conv;
+      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
+      item->SetDouble(conv.d);
+      break;
+    }
+    case DexFile::kDexAnnotationString: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetStringId(GetStringId(string_index));
+      break;
+    }
+    case DexFile::kDexAnnotationType: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetTypeId(GetTypeId(string_index));
+      break;
+    }
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum: {
+      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetFieldId(GetFieldId(field_index));
+      break;
+    }
+    case DexFile::kDexAnnotationMethod: {
+      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->SetMethodId(GetMethodId(method_index));
+      break;
+    }
+    case DexFile::kDexAnnotationArray: {
+      EncodedValueVector* values = new EncodedValueVector();
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      // Decode all elements.
+      for (uint32_t i = 0; i < size; i++) {
+        values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(data)));
+      }
+      item->SetEncodedArray(new EncodedArrayItem(values));
+      break;
+    }
+    case DexFile::kDexAnnotationAnnotation: {
+      AnnotationElementVector* elements = new AnnotationElementVector();
+      const uint32_t type_idx = DecodeUnsignedLeb128(data);
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      // Decode all name=value pairs.
+      for (uint32_t i = 0; i < size; i++) {
+        const uint32_t name_index = DecodeUnsignedLeb128(data);
+        elements->push_back(std::unique_ptr<AnnotationElement>(
+            new AnnotationElement(GetStringId(name_index), ReadEncodedValue(data))));
+      }
+      item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
+      break;
+    }
+    case DexFile::kDexAnnotationNull:
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      item->SetBoolean(length != 0);
+      break;
+    default:
+      break;
+  }
+}
+
+void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::StringId& disk_string_id = dex_file.GetStringId(i);
+  StringData* string_data = new StringData(dex_file.GetStringData(disk_string_id));
+  string_datas_.AddItem(string_data, disk_string_id.string_data_off_);
+
+  StringId* string_id = new StringId(string_data);
+  string_ids_.AddIndexedItem(string_id, StringIdsOffset() + i * StringId::ItemSize(), i);
+}
+
+void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
+  TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_));
+  type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
+}
+
+void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
+  const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
+  TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_, true);
+
+  ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_),
+                                  GetTypeId(disk_proto_id.return_type_idx_),
+                                  parameter_type_list);
+  proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
+}
+
+void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
+  FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_),
+                                  GetTypeId(disk_field_id.type_idx_),
+                                  GetStringId(disk_field_id.name_idx_));
+  field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
+}
+
+void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
+  const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
+  MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_),
+                                     GetProtoId(disk_method_id.proto_idx_),
+                                     GetStringId(disk_method_id.name_idx_));
+  method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
+}
+
+void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
+  const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
+  const TypeId* class_type = GetTypeId(disk_class_def.class_idx_);
+  uint32_t access_flags = disk_class_def.access_flags_;
+  const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
+
+  const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
+  TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_, false);
+
+  const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
+  // Annotations.
+  AnnotationsDirectoryItem* annotations = nullptr;
+  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
+      dex_file.GetAnnotationsDirectory(disk_class_def);
+  if (disk_annotations_directory_item != nullptr) {
+    annotations = CreateAnnotationsDirectoryItem(
+        dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
+  }
+  // Static field initializers.
+  const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
+  EncodedArrayItem* static_values =
+      CreateEncodedArrayItem(static_data, disk_class_def.static_values_off_);
+  ClassData* class_data = CreateClassData(
+      dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
+  ClassDef* class_def = new ClassDef(class_type, access_flags, superclass, interfaces_type_list,
+                                     source_file, annotations, static_values, class_data);
+  class_defs_.AddIndexedItem(class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
+}
+
+TypeList* Collections::CreateTypeList(
+    const DexFile::TypeList* dex_type_list, uint32_t offset, bool allow_empty) {
+  if (dex_type_list == nullptr && !allow_empty) {
+    return nullptr;
+  }
+  // TODO: Create more efficient lookup for existing type lists.
+  for (std::unique_ptr<TypeList>& type_list : TypeLists()) {
+    if (type_list->GetOffset() == offset) {
+      return type_list.get();
+    }
+  }
+  TypeIdVector* type_vector = new TypeIdVector();
+  uint32_t size = dex_type_list == nullptr ? 0 : dex_type_list->Size();
+  for (uint32_t index = 0; index < size; ++index) {
+    type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_));
+  }
+  TypeList* new_type_list = new TypeList(type_vector);
+  type_lists_.AddItem(new_type_list, offset);
+  return new_type_list;
+}
+
+EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset) {
+  if (static_data == nullptr) {
+    return nullptr;
+  }
+  uint32_t size = DecodeUnsignedLeb128(&static_data);
+  EncodedValueVector* values = new EncodedValueVector();
+  for (uint32_t i = 0; i < size; ++i) {
+    values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(&static_data)));
+  }
+  // TODO: Calculate the size of the encoded array.
+  EncodedArrayItem* encoded_array_item = new EncodedArrayItem(values);
+  encoded_array_items_.AddItem(encoded_array_item, offset);
+  return encoded_array_item;
+}
+
+AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
+                                                  uint32_t offset) {
+  uint8_t visibility = annotation->visibility_;
+  const uint8_t* annotation_data = annotation->annotation_;
+  EncodedValue* encoded_value =
+      ReadEncodedValue(&annotation_data, DexFile::kDexAnnotationAnnotation, 0);
+  // TODO: Calculate the size of the annotation.
+  AnnotationItem* annotation_item =
+      new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation());
+  annotation_items_.AddItem(annotation_item, offset);
+  return annotation_item;
+}
+
+
+AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
+    const DexFile::AnnotationSetItem& disk_annotations_item, uint32_t offset) {
+  if (disk_annotations_item.size_ == 0) {
+    return nullptr;
+  }
+  std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
+  for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
+    const DexFile::AnnotationItem* annotation =
+        dex_file.GetAnnotationItem(&disk_annotations_item, i);
+    if (annotation == nullptr) {
+      continue;
+    }
+    AnnotationItem* annotation_item =
+        CreateAnnotationItem(annotation, disk_annotations_item.entries_[i]);
+    items->push_back(annotation_item);
+  }
+  AnnotationSetItem* annotation_set_item = new AnnotationSetItem(items);
+  annotation_set_items_.AddItem(annotation_set_item, offset);
+  return annotation_set_item;
+}
+
+AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
+    const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
+  const DexFile::AnnotationSetItem* class_set_item =
+      dex_file.GetClassAnnotationSet(disk_annotations_item);
+  AnnotationSetItem* class_annotation = nullptr;
+  if (class_set_item != nullptr) {
+    uint32_t offset = disk_annotations_item->class_annotations_off_;
+    class_annotation = CreateAnnotationSetItem(dex_file, *class_set_item, offset);
+  }
+  const DexFile::FieldAnnotationsItem* fields =
+      dex_file.GetFieldAnnotations(disk_annotations_item);
+  FieldAnnotationVector* field_annotations = nullptr;
+  if (fields != nullptr) {
+    field_annotations = new FieldAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
+      FieldId* field_id = GetFieldId(fields[i].field_idx_);
+      const DexFile::AnnotationSetItem* field_set_item =
+          dex_file.GetFieldAnnotationSetItem(fields[i]);
+      uint32_t annotation_set_offset = fields[i].annotations_off_;
+      AnnotationSetItem* annotation_set_item =
+          CreateAnnotationSetItem(dex_file, *field_set_item, annotation_set_offset);
+      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
+          new FieldAnnotation(field_id, annotation_set_item)));
+    }
+  }
+  const DexFile::MethodAnnotationsItem* methods =
+      dex_file.GetMethodAnnotations(disk_annotations_item);
+  MethodAnnotationVector* method_annotations = nullptr;
+  if (methods != nullptr) {
+    method_annotations = new MethodAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
+      MethodId* method_id = GetMethodId(methods[i].method_idx_);
+      const DexFile::AnnotationSetItem* method_set_item =
+          dex_file.GetMethodAnnotationSetItem(methods[i]);
+      uint32_t annotation_set_offset = methods[i].annotations_off_;
+      AnnotationSetItem* annotation_set_item =
+          CreateAnnotationSetItem(dex_file, *method_set_item, annotation_set_offset);
+      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
+          new MethodAnnotation(method_id, annotation_set_item)));
+    }
+  }
+  const DexFile::ParameterAnnotationsItem* parameters =
+      dex_file.GetParameterAnnotations(disk_annotations_item);
+  ParameterAnnotationVector* parameter_annotations = nullptr;
+  if (parameters != nullptr) {
+    parameter_annotations = new ParameterAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
+      MethodId* method_id = GetMethodId(parameters[i].method_idx_);
+      const DexFile::AnnotationSetRefList* list =
+          dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
+      parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
+          GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
+    }
+  }
+  // TODO: Calculate the size of the annotations directory.
+  AnnotationsDirectoryItem* annotations_directory_item = new AnnotationsDirectoryItem(
+      class_annotation, field_annotations, method_annotations, parameter_annotations);
+  annotations_directory_items_.AddItem(annotations_directory_item, offset);
+  return annotations_directory_item;
+}
+
+ParameterAnnotation* Collections::GenerateParameterAnnotation(
+    const DexFile& dex_file, MethodId* method_id,
+    const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
+  std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
+  for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
+    const DexFile::AnnotationSetItem* annotation_set_item =
+        dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
+    uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
+    annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset));
+  }
+  AnnotationSetRefList* new_ref_list = new AnnotationSetRefList(annotations);
+  annotation_set_ref_lists_.AddItem(new_ref_list, offset);
+  return new ParameterAnnotation(method_id, new_ref_list);
+}
+
+CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
+                                      const DexFile::CodeItem& disk_code_item, uint32_t offset) {
+  uint16_t registers_size = disk_code_item.registers_size_;
+  uint16_t ins_size = disk_code_item.ins_size_;
+  uint16_t outs_size = disk_code_item.outs_size_;
+  uint32_t tries_size = disk_code_item.tries_size_;
+
+  // TODO: Calculate the size of the debug info.
+  const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
+  DebugInfoItem* debug_info = nullptr;
+  if (debug_info_stream != nullptr) {
+    debug_info = new DebugInfoItem();
+    debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
+  }
+
+  uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+  uint16_t* insns = new uint16_t[insns_size];
+  memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
+
+  TryItemVector* tries = nullptr;
+  if (tries_size > 0) {
+    tries = new TryItemVector();
+    for (uint32_t i = 0; i < tries_size; ++i) {
+      const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+      uint32_t start_addr = disk_try_item->start_addr_;
+      uint16_t insn_count = disk_try_item->insn_count_;
+      CatchHandlerVector* handlers = new CatchHandlerVector();
+      for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
+        const uint16_t type_index = it.GetHandlerTypeIndex();
+        const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
+        handlers->push_back(std::unique_ptr<const CatchHandler>(
+            new CatchHandler(type_id, it.GetHandlerAddress())));
+      }
+      TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
+      tries->push_back(std::unique_ptr<const TryItem>(try_item));
+    }
+  }
+  // TODO: Calculate the size of the code item.
+  CodeItem* code_item =
+      new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries);
+  code_items_.AddItem(code_item, offset);
+  return code_item;
+}
+
+MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
+  MethodId* method_item = GetMethodId(cdii.GetMemberIndex());
+  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
+  CodeItem* code_item = nullptr;
+  DebugInfoItem* debug_info = nullptr;
+  if (disk_code_item != nullptr) {
+    code_item = CreateCodeItem(dex_file, *disk_code_item, cdii.GetMethodCodeItemOffset());
+    debug_info = code_item->DebugInfo();
+  }
+  if (debug_info != nullptr) {
+    bool is_static = (access_flags & kAccStatic) != 0;
+    dex_file.DecodeDebugLocalInfo(
+        disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
+    dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
+  }
+  return new MethodItem(access_flags, method_item, code_item);
+}
+
+ClassData* Collections::CreateClassData(
+    const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
+  // Read the fields and methods defined by the class, resolving the circular reference from those
+  // to classes by setting class at the same time.
+  ClassData* class_data = nullptr;
+  if (encoded_data != nullptr) {
+    ClassDataItemIterator cdii(dex_file, encoded_data);
+    // Static fields.
+    FieldItemVector* static_fields = new FieldItemVector();
+    for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) {
+      FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
+    }
+    // Instance fields.
+    FieldItemVector* instance_fields = new FieldItemVector();
+    for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) {
+      FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      instance_fields->push_back(
+          std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
+    }
+    // Direct methods.
+    MethodItemVector* direct_methods = new MethodItemVector();
+    for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) {
+      direct_methods->push_back(
+          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
+    }
+    // Virtual methods.
+    MethodItemVector* virtual_methods = new MethodItemVector();
+    for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) {
+      virtual_methods->push_back(
+          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
+    }
+    // TODO: Calculate the size of the class data.
+    class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+    class_datas_.AddItem(class_data, offset);
+  }
+  return class_data;
+}
+
+}  // namespace dex_ir
+}  // namespace art
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index cbb4404..6ae9f1c 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -23,18 +23,23 @@
 #include <stdint.h>
 
 #include "dex_file-inl.h"
+#include "leb128.h"
 
 namespace art {
 namespace dex_ir {
 
 // Forward declarations for classes used in containers or pointed to.
+class AnnotationItem;
 class AnnotationsDirectoryItem;
 class AnnotationSetItem;
-class ArrayItem;
+class AnnotationSetRefList;
 class ClassData;
 class ClassDef;
 class CodeItem;
 class DebugInfoItem;
+class EncodedAnnotation;
+class EncodedArrayItem;
+class EncodedValue;
 class FieldId;
 class FieldItem;
 class Header;
@@ -42,10 +47,22 @@
 class MapItem;
 class MethodId;
 class MethodItem;
+class ParameterAnnotation;
 class ProtoId;
+class StringData;
 class StringId;
 class TryItem;
 class TypeId;
+class TypeList;
+
+// Item size constants.
+static constexpr size_t kHeaderItemSize = 112;
+static constexpr size_t kStringIdItemSize = 4;
+static constexpr size_t kTypeIdItemSize = 4;
+static constexpr size_t kProtoIdItemSize = 12;
+static constexpr size_t kFieldIdItemSize = 8;
+static constexpr size_t kMethodIdItemSize = 8;
+static constexpr size_t kClassDefItemSize = 32;
 
 // Visitor support
 class AbstractDispatcher {
@@ -54,6 +71,7 @@
   virtual ~AbstractDispatcher() { }
 
   virtual void Dispatch(Header* header) = 0;
+  virtual void Dispatch(const StringData* string_data) = 0;
   virtual void Dispatch(const StringId* string_id) = 0;
   virtual void Dispatch(const TypeId* type_id) = 0;
   virtual void Dispatch(const ProtoId* proto_id) = 0;
@@ -63,11 +81,13 @@
   virtual void Dispatch(ClassDef* class_def) = 0;
   virtual void Dispatch(FieldItem* field_item) = 0;
   virtual void Dispatch(MethodItem* method_item) = 0;
-  virtual void Dispatch(ArrayItem* array_item) = 0;
+  virtual void Dispatch(EncodedArrayItem* array_item) = 0;
   virtual void Dispatch(CodeItem* code_item) = 0;
   virtual void Dispatch(TryItem* try_item) = 0;
   virtual void Dispatch(DebugInfoItem* debug_info_item) = 0;
+  virtual void Dispatch(AnnotationItem* annotation_item) = 0;
   virtual void Dispatch(AnnotationSetItem* annotation_set_item) = 0;
+  virtual void Dispatch(AnnotationSetRefList* annotation_set_ref_list) = 0;
   virtual void Dispatch(AnnotationsDirectoryItem* annotations_directory_item) = 0;
   virtual void Dispatch(MapList* map_list) = 0;
   virtual void Dispatch(MapItem* map_item) = 0;
@@ -82,9 +102,14 @@
   CollectionWithOffset() = default;
   std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
   // Read-time support methods
-  void AddWithPosition(uint32_t position, T* object) {
+  void AddItem(T* object, uint32_t offset) {
+    object->SetOffset(offset);
     collection_.push_back(std::unique_ptr<T>(object));
-    collection_.back()->SetOffset(position);
+  }
+  void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
+    object->SetOffset(offset);
+    object->SetIndex(index);
+    collection_.push_back(std::unique_ptr<T>(object));
   }
   // Ordinary object insertion into collection.
   void Insert(T object ATTRIBUTE_UNUSED) {
@@ -98,18 +123,160 @@
  private:
   std::vector<std::unique_ptr<T>> collection_;
   uint32_t offset_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset);
 };
 
+class Collections {
+ public:
+  Collections() = default;
+
+  std::vector<std::unique_ptr<StringId>>& StringIds() { return string_ids_.Collection(); }
+  std::vector<std::unique_ptr<TypeId>>& TypeIds() { return type_ids_.Collection(); }
+  std::vector<std::unique_ptr<ProtoId>>& ProtoIds() { return proto_ids_.Collection(); }
+  std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
+  std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
+  std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
+
+  std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
+  std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
+      { return encoded_array_items_.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);
+  void CreateFieldId(const DexFile& dex_file, uint32_t i);
+  void CreateMethodId(const DexFile& dex_file, uint32_t i);
+  void CreateClassDef(const DexFile& dex_file, uint32_t i);
+
+  TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset, bool allow_empty);
+  EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset);
+  AnnotationItem* CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset);
+  AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
+      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);
+  ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
+
+  StringId* GetStringId(uint32_t index) { return StringIds()[index].get(); }
+  TypeId* GetTypeId(uint32_t index) { return TypeIds()[index].get(); }
+  ProtoId* GetProtoId(uint32_t index) { return ProtoIds()[index].get(); }
+  FieldId* GetFieldId(uint32_t index) { return FieldIds()[index].get(); }
+  MethodId* GetMethodId(uint32_t index) { return MethodIds()[index].get(); }
+  ClassDef* GetClassDef(uint32_t index) { return ClassDefs()[index].get(); }
+
+  StringId* GetStringIdOrNullPtr(uint32_t index) {
+    return index == DexFile::kDexNoIndex ? nullptr : GetStringId(index);
+  }
+  TypeId* GetTypeIdOrNullPtr(uint16_t index) {
+    return index == DexFile::kDexNoIndex16 ? nullptr : GetTypeId(index);
+  }
+
+  uint32_t StringIdsOffset() const { return string_ids_.GetOffset(); }
+  uint32_t TypeIdsOffset() const { return type_ids_.GetOffset(); }
+  uint32_t ProtoIdsOffset() const { return proto_ids_.GetOffset(); }
+  uint32_t FieldIdsOffset() const { return field_ids_.GetOffset(); }
+  uint32_t MethodIdsOffset() const { return method_ids_.GetOffset(); }
+  uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
+  uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); }
+  uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); }
+  uint32_t EncodedArrayOffset() const { return encoded_array_items_.GetOffset(); }
+  uint32_t AnnotationOffset() const { return annotation_items_.GetOffset(); }
+  uint32_t AnnotationSetOffset() const { return annotation_set_items_.GetOffset(); }
+  uint32_t AnnotationSetRefListsOffset() const { return annotation_set_ref_lists_.GetOffset(); }
+  uint32_t AnnotationsDirectoryOffset() const { return annotations_directory_items_.GetOffset(); }
+  uint32_t DebugInfoOffset() const { return debug_info_items_.GetOffset(); }
+  uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
+  uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
+
+  void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
+  void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
+  void SetProtoIdsOffset(uint32_t new_offset) { proto_ids_.SetOffset(new_offset); }
+  void SetFieldIdsOffset(uint32_t new_offset) { field_ids_.SetOffset(new_offset); }
+  void SetMethodIdsOffset(uint32_t new_offset) { method_ids_.SetOffset(new_offset); }
+  void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
+  void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); }
+  void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); }
+  void SetEncodedArrayOffset(uint32_t new_offset) { encoded_array_items_.SetOffset(new_offset); }
+  void SetAnnotationOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); }
+  void SetAnnotationSetOffset(uint32_t new_offset) { annotation_set_items_.SetOffset(new_offset); }
+  void SetAnnotationSetRefListsOffset(uint32_t new_offset)
+      { annotation_set_ref_lists_.SetOffset(new_offset); }
+  void SetAnnotationsDirectoryOffset(uint32_t new_offset)
+      { annotations_directory_items_.SetOffset(new_offset); }
+  void SetDebugInfoOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
+  void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
+  void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
+
+  uint32_t StringIdsSize() const { return string_ids_.Size(); }
+  uint32_t TypeIdsSize() const { return type_ids_.Size(); }
+  uint32_t ProtoIdsSize() const { return proto_ids_.Size(); }
+  uint32_t FieldIdsSize() const { return field_ids_.Size(); }
+  uint32_t MethodIdsSize() const { return method_ids_.Size(); }
+  uint32_t ClassDefsSize() const { return class_defs_.Size(); }
+
+ private:
+  EncodedValue* ReadEncodedValue(const uint8_t** data);
+  EncodedValue* ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length);
+  void ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length, EncodedValue* item);
+
+  ParameterAnnotation* GenerateParameterAnnotation(const DexFile& dex_file, MethodId* method_id,
+      const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
+  MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
+
+  CollectionWithOffset<StringId> string_ids_;
+  CollectionWithOffset<TypeId> type_ids_;
+  CollectionWithOffset<ProtoId> proto_ids_;
+  CollectionWithOffset<FieldId> field_ids_;
+  CollectionWithOffset<MethodId> method_ids_;
+  CollectionWithOffset<ClassDef> class_defs_;
+
+  CollectionWithOffset<StringData> string_datas_;
+  CollectionWithOffset<TypeList> type_lists_;
+  CollectionWithOffset<EncodedArrayItem> encoded_array_items_;
+  CollectionWithOffset<AnnotationItem> annotation_items_;
+  CollectionWithOffset<AnnotationSetItem> annotation_set_items_;
+  CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_;
+  CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_;
+  CollectionWithOffset<DebugInfoItem> debug_info_items_;
+  CollectionWithOffset<CodeItem> code_items_;
+  CollectionWithOffset<ClassData> class_datas_;
+
+  DISALLOW_COPY_AND_ASSIGN(Collections);
+};
+
 class Item {
  public:
+  Item() { }
   virtual ~Item() { }
 
   uint32_t GetOffset() const { return offset_; }
+  uint32_t GetSize() const { return size_; }
   void SetOffset(uint32_t offset) { offset_ = offset; }
+  void SetSize(uint32_t size) { size_ = size; }
 
  protected:
+  Item(uint32_t offset, uint32_t size) : offset_(offset), size_(size) { }
+
   uint32_t offset_ = 0;
+  uint32_t size_ = 0;
+};
+
+class IndexedItem : public Item {
+ public:
+  IndexedItem() { }
+  virtual ~IndexedItem() { }
+
+  uint32_t GetIndex() const { return index_; }
+  void SetIndex(uint32_t index) { index_ = index; }
+
+ protected:
+  IndexedItem(uint32_t offset, uint32_t size, uint32_t index)
+      : Item(offset, size), index_(index) { }
+
+  uint32_t index_ = 0;
 };
 
 class Header : public Item {
@@ -124,7 +291,8 @@
          uint32_t link_offset,
          uint32_t data_size,
          uint32_t data_offset)
-      : checksum_(checksum),
+      : Item(0, kHeaderItemSize),
+        checksum_(checksum),
         endian_tag_(endian_tag),
         file_size_(file_size),
         header_size_(header_size),
@@ -137,6 +305,8 @@
   }
   ~Header() OVERRIDE { }
 
+  static size_t ItemSize() { return kHeaderItemSize; }
+
   const uint8_t* Magic() const { return magic_; }
   uint32_t Checksum() const { return checksum_; }
   const uint8_t* Signature() const { return signature_; }
@@ -159,39 +329,7 @@
   void SetDataSize(uint32_t new_data_size) { data_size_ = new_data_size; }
   void SetDataOffset(uint32_t new_data_offset) { data_offset_ = new_data_offset; }
 
-  // Collections.
-  std::vector<std::unique_ptr<StringId>>& StringIds() { return string_ids_.Collection(); }
-  std::vector<std::unique_ptr<TypeId>>& TypeIds() { return type_ids_.Collection(); }
-  std::vector<std::unique_ptr<ProtoId>>& ProtoIds() { return proto_ids_.Collection(); }
-  std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
-  std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
-  std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
-  uint32_t StringIdsOffset() const { return string_ids_.GetOffset(); }
-  uint32_t TypeIdsOffset() const { return type_ids_.GetOffset(); }
-  uint32_t ProtoIdsOffset() const { return proto_ids_.GetOffset(); }
-  uint32_t FieldIdsOffset() const { return field_ids_.GetOffset(); }
-  uint32_t MethodIdsOffset() const { return method_ids_.GetOffset(); }
-  uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
-  void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
-  void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
-  void SetProtoIdsOffset(uint32_t new_offset) { proto_ids_.SetOffset(new_offset); }
-  void SetFieldIdsOffset(uint32_t new_offset) { field_ids_.SetOffset(new_offset); }
-  void SetMethodIdsOffset(uint32_t new_offset) { method_ids_.SetOffset(new_offset); }
-  void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
-  uint32_t StringIdsSize() const { return string_ids_.Size(); }
-  uint32_t TypeIdsSize() const { return type_ids_.Size(); }
-  uint32_t ProtoIdsSize() const { return proto_ids_.Size(); }
-  uint32_t FieldIdsSize() const { return field_ids_.Size(); }
-  uint32_t MethodIdsSize() const { return method_ids_.Size(); }
-  uint32_t ClassDefsSize() const { return class_defs_.Size(); }
-
-  TypeId* GetTypeIdOrNullPtr(uint16_t index) {
-    return index == DexFile::kDexNoIndex16 ? nullptr : TypeIds()[index].get();
-  }
-
-  StringId* GetStringIdOrNullPtr(uint32_t index) {
-    return index == DexFile::kDexNoIndex ? nullptr : StringIds()[index].get();
-  }
+  Collections& GetCollections() { return collections_; }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
@@ -207,19 +345,16 @@
   uint32_t data_size_;
   uint32_t data_offset_;
 
-  CollectionWithOffset<StringId> string_ids_;
-  CollectionWithOffset<TypeId> type_ids_;
-  CollectionWithOffset<ProtoId> proto_ids_;
-  CollectionWithOffset<FieldId> field_ids_;
-  CollectionWithOffset<MethodId> method_ids_;
-  CollectionWithOffset<ClassDef> class_defs_;
+  Collections collections_;
+
   DISALLOW_COPY_AND_ASSIGN(Header);
 };
 
-class StringId : public Item {
+class StringData : public Item {
  public:
-  explicit StringId(const char* data) : data_(strdup(data)) { }
-  ~StringId() OVERRIDE { }
+  explicit StringData(const char* data) : data_(strdup(data)) {
+    size_ = UnsignedLeb128Size(strlen(data)) + strlen(data);
+  }
 
   const char* Data() const { return data_.get(); }
 
@@ -227,50 +362,95 @@
 
  private:
   std::unique_ptr<const char> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(StringData);
+};
+
+class StringId : public IndexedItem {
+ public:
+  explicit StringId(StringData* string_data) : string_data_(string_data) {
+    size_ = kStringIdItemSize;
+  }
+  ~StringId() OVERRIDE { }
+
+  static size_t ItemSize() { return kStringIdItemSize; }
+
+  const char* Data() const { return string_data_->Data(); }
+  StringData* DataItem() const { return string_data_; }
+
+  void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
+
+ private:
+  StringData* string_data_;
+
   DISALLOW_COPY_AND_ASSIGN(StringId);
 };
 
-class TypeId : public Item {
+class TypeId : public IndexedItem {
  public:
-  explicit TypeId(StringId* string_id) : string_id_(string_id) { }
+  explicit TypeId(StringId* string_id) : string_id_(string_id) { size_ = kTypeIdItemSize; }
   ~TypeId() OVERRIDE { }
 
+  static size_t ItemSize() { return kTypeIdItemSize; }
+
   StringId* GetStringId() const { return string_id_; }
 
   void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
 
  private:
   StringId* string_id_;
+
   DISALLOW_COPY_AND_ASSIGN(TypeId);
 };
 
 using TypeIdVector = std::vector<const TypeId*>;
 
-class ProtoId : public Item {
+class TypeList : public Item {
  public:
-  ProtoId(const StringId* shorty, const TypeId* return_type, TypeIdVector* parameters)
-      : shorty_(shorty), return_type_(return_type), parameters_(parameters) { }
+  explicit TypeList(TypeIdVector* type_list) : type_list_(type_list) {
+    size_ = sizeof(uint32_t) + (type_list->size() * sizeof(uint16_t));
+  }
+  ~TypeList() OVERRIDE { }
+
+  const TypeIdVector* GetTypeList() const { return type_list_.get(); }
+
+ private:
+  std::unique_ptr<TypeIdVector> type_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeList);
+};
+
+class ProtoId : public IndexedItem {
+ public:
+  ProtoId(const StringId* shorty, const TypeId* return_type, TypeList* parameters)
+      : shorty_(shorty), return_type_(return_type), parameters_(parameters)
+      { size_ = kProtoIdItemSize; }
   ~ProtoId() OVERRIDE { }
 
+  static size_t ItemSize() { return kProtoIdItemSize; }
+
   const StringId* Shorty() const { return shorty_; }
   const TypeId* ReturnType() const { return return_type_; }
-  const std::vector<const TypeId*>& Parameters() const { return *parameters_; }
+  const TypeIdVector& Parameters() const { return *parameters_->GetTypeList(); }
 
   void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
 
  private:
   const StringId* shorty_;
   const TypeId* return_type_;
-  std::unique_ptr<TypeIdVector> parameters_;
+  TypeList* parameters_;
+
   DISALLOW_COPY_AND_ASSIGN(ProtoId);
 };
 
-class FieldId : public Item {
+class FieldId : public IndexedItem {
  public:
   FieldId(const TypeId* klass, const TypeId* type, const StringId* name)
-      : class_(klass), type_(type), name_(name) { }
+      : class_(klass), type_(type), name_(name) { size_ = kFieldIdItemSize; }
   ~FieldId() OVERRIDE { }
 
+  static size_t ItemSize() { return kFieldIdItemSize; }
+
   const TypeId* Class() const { return class_; }
   const TypeId* Type() const { return type_; }
   const StringId* Name() const { return name_; }
@@ -281,15 +461,18 @@
   const TypeId* class_;
   const TypeId* type_;
   const StringId* name_;
+
   DISALLOW_COPY_AND_ASSIGN(FieldId);
 };
 
-class MethodId : public Item {
+class MethodId : public IndexedItem {
  public:
   MethodId(const TypeId* klass, const ProtoId* proto, const StringId* name)
-      : class_(klass), proto_(proto), name_(name) { }
+      : class_(klass), proto_(proto), name_(name) { size_ = kMethodIdItemSize; }
   ~MethodId() OVERRIDE { }
 
+  static size_t ItemSize() { return kMethodIdItemSize; }
+
   const TypeId* Class() const { return class_; }
   const ProtoId* Proto() const { return proto_; }
   const StringId* Name() const { return name_; }
@@ -300,6 +483,7 @@
   const TypeId* class_;
   const ProtoId* proto_;
   const StringId* name_;
+
   DISALLOW_COPY_AND_ASSIGN(MethodId);
 };
 
@@ -317,6 +501,7 @@
  private:
   uint32_t access_flags_;
   const FieldId* field_id_;
+
   DISALLOW_COPY_AND_ASSIGN(FieldItem);
 };
 
@@ -330,93 +515,126 @@
 
   uint32_t GetAccessFlags() const { return access_flags_; }
   const MethodId* GetMethodId() const { return method_id_; }
-  const CodeItem* GetCodeItem() const { return code_.get(); }
+  const CodeItem* GetCodeItem() const { return code_; }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
   uint32_t access_flags_;
   const MethodId* method_id_;
-  std::unique_ptr<const CodeItem> code_;
+  const CodeItem* code_;
+
   DISALLOW_COPY_AND_ASSIGN(MethodItem);
 };
 
 using MethodItemVector = std::vector<std::unique_ptr<MethodItem>>;
 
-class ArrayItem : public Item {
+class EncodedValue {
  public:
-  class NameValuePair {
-   public:
-    NameValuePair(StringId* name, ArrayItem* value)
-        : name_(name), value_(value) { }
-
-    StringId* Name() const { return name_; }
-    ArrayItem* Value() const { return value_.get(); }
-
-   private:
-    StringId* name_;
-    std::unique_ptr<ArrayItem> value_;
-    DISALLOW_COPY_AND_ASSIGN(NameValuePair);
-  };
-
-  struct ArrayItemVariant {
-   public:
-    union {
-      bool bool_val_;
-      int8_t byte_val_;
-      int16_t short_val_;
-      uint16_t char_val_;
-      int32_t int_val_;
-      int64_t long_val_;
-      float float_val_;
-      double double_val_;
-      StringId* string_val_;
-      FieldId* field_val_;
-      MethodId* method_val_;
-    } u_;
-    std::unique_ptr<std::vector<std::unique_ptr<ArrayItem>>> annotation_array_val_;
-    struct {
-      StringId* string_;
-      std::unique_ptr<std::vector<std::unique_ptr<NameValuePair>>> array_;
-    } annotation_annotation_val_;
-  };
-
-  explicit ArrayItem(uint8_t type) : type_(type) { }
-  ~ArrayItem() OVERRIDE { }
+  explicit EncodedValue(uint8_t type) : type_(type) { }
 
   int8_t Type() const { return type_; }
-  bool GetBoolean() const { return item_.u_.bool_val_; }
-  int8_t GetByte() const { return item_.u_.byte_val_; }
-  int16_t GetShort() const { return item_.u_.short_val_; }
-  uint16_t GetChar() const { return item_.u_.char_val_; }
-  int32_t GetInt() const { return item_.u_.int_val_; }
-  int64_t GetLong() const { return item_.u_.long_val_; }
-  float GetFloat() const { return item_.u_.float_val_; }
-  double GetDouble() const { return item_.u_.double_val_; }
-  StringId* GetStringId() const { return item_.u_.string_val_; }
-  FieldId* GetFieldId() const { return item_.u_.field_val_; }
-  MethodId* GetMethodId() const { return item_.u_.method_val_; }
-  std::vector<std::unique_ptr<ArrayItem>>* GetAnnotationArray() const {
-    return item_.annotation_array_val_.get();
-  }
-  StringId* GetAnnotationAnnotationString() const {
-    return item_.annotation_annotation_val_.string_;
-  }
-  std::vector<std::unique_ptr<NameValuePair>>* GetAnnotationAnnotationNameValuePairArray() const {
-    return item_.annotation_annotation_val_.array_.get();
-  }
-  // Used to construct the item union.  Ugly, but necessary.
-  ArrayItemVariant* GetArrayItemVariant() { return &item_; }
 
-  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+  void SetBoolean(bool z) { u_.bool_val_ = z; }
+  void SetByte(int8_t b) { u_.byte_val_ = b; }
+  void SetShort(int16_t s) { u_.short_val_ = s; }
+  void SetChar(uint16_t c) { u_.char_val_ = c; }
+  void SetInt(int32_t i) { u_.int_val_ = i; }
+  void SetLong(int64_t l) { u_.long_val_ = l; }
+  void SetFloat(float f) { u_.float_val_ = f; }
+  void SetDouble(double d) { u_.double_val_ = d; }
+  void SetStringId(StringId* string_id) { u_.string_val_ = string_id; }
+  void SetTypeId(TypeId* type_id) { u_.type_val_ = type_id; }
+  void SetFieldId(FieldId* field_id) { u_.field_val_ = field_id; }
+  void SetMethodId(MethodId* method_id) { u_.method_val_ = method_id; }
+  void SetEncodedArray(EncodedArrayItem* encoded_array) { encoded_array_.reset(encoded_array); }
+  void SetEncodedAnnotation(EncodedAnnotation* encoded_annotation)
+      { encoded_annotation_.reset(encoded_annotation); }
+
+  bool GetBoolean() const { return u_.bool_val_; }
+  int8_t GetByte() const { return u_.byte_val_; }
+  int16_t GetShort() const { return u_.short_val_; }
+  uint16_t GetChar() const { return u_.char_val_; }
+  int32_t GetInt() const { return u_.int_val_; }
+  int64_t GetLong() const { return u_.long_val_; }
+  float GetFloat() const { return u_.float_val_; }
+  double GetDouble() const { return u_.double_val_; }
+  StringId* GetStringId() const { return u_.string_val_; }
+  TypeId* GetTypeId() const { return u_.type_val_; }
+  FieldId* GetFieldId() const { return u_.field_val_; }
+  MethodId* GetMethodId() const { return u_.method_val_; }
+  EncodedArrayItem* GetEncodedArray() const { return encoded_array_.get(); }
+  EncodedAnnotation* GetEncodedAnnotation() const { return encoded_annotation_.get(); }
+
+  EncodedAnnotation* ReleaseEncodedAnnotation() { return encoded_annotation_.release(); }
 
  private:
   uint8_t type_;
-  ArrayItemVariant item_;
-  DISALLOW_COPY_AND_ASSIGN(ArrayItem);
+  union {
+    bool bool_val_;
+    int8_t byte_val_;
+    int16_t short_val_;
+    uint16_t char_val_;
+    int32_t int_val_;
+    int64_t long_val_;
+    float float_val_;
+    double double_val_;
+    StringId* string_val_;
+    TypeId* type_val_;
+    FieldId* field_val_;
+    MethodId* method_val_;
+  } u_;
+  std::unique_ptr<EncodedArrayItem> encoded_array_;
+  std::unique_ptr<EncodedAnnotation> encoded_annotation_;
+
+  DISALLOW_COPY_AND_ASSIGN(EncodedValue);
 };
 
-using ArrayItemVector = std::vector<std::unique_ptr<ArrayItem>>;
+using EncodedValueVector = std::vector<std::unique_ptr<EncodedValue>>;
+
+class AnnotationElement {
+ public:
+  AnnotationElement(StringId* name, EncodedValue* value) : name_(name), value_(value) { }
+
+  StringId* GetName() const { return name_; }
+  EncodedValue* GetValue() const { return value_.get(); }
+
+ private:
+  StringId* name_;
+  std::unique_ptr<EncodedValue> value_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnnotationElement);
+};
+
+using AnnotationElementVector = std::vector<std::unique_ptr<AnnotationElement>>;
+
+class EncodedAnnotation {
+ public:
+  EncodedAnnotation(TypeId* type, AnnotationElementVector* elements)
+      : type_(type), elements_(elements) { }
+
+  TypeId* GetType() const { return type_; }
+  AnnotationElementVector* GetAnnotationElements() const { return elements_.get(); }
+
+ private:
+  TypeId* type_;
+  std::unique_ptr<AnnotationElementVector> elements_;
+
+  DISALLOW_COPY_AND_ASSIGN(EncodedAnnotation);
+};
+
+class EncodedArrayItem : public Item {
+ public:
+  explicit EncodedArrayItem(EncodedValueVector* encoded_values)
+      : encoded_values_(encoded_values) { }
+
+  EncodedValueVector* GetEncodedValues() const { return encoded_values_.get(); }
+
+ private:
+  std::unique_ptr<EncodedValueVector> encoded_values_;
+
+  DISALLOW_COPY_AND_ASSIGN(EncodedArrayItem);
+};
 
 class ClassData : public Item {
  public:
@@ -442,42 +660,43 @@
   std::unique_ptr<FieldItemVector> instance_fields_;
   std::unique_ptr<MethodItemVector> direct_methods_;
   std::unique_ptr<MethodItemVector> virtual_methods_;
+
   DISALLOW_COPY_AND_ASSIGN(ClassData);
 };
 
-class ClassDef : public Item {
+class ClassDef : public IndexedItem {
  public:
   ClassDef(const TypeId* class_type,
            uint32_t access_flags,
            const TypeId* superclass,
-           TypeIdVector* interfaces,
-           uint32_t interfaces_offset,
+           TypeList* interfaces,
            const StringId* source_file,
            AnnotationsDirectoryItem* annotations,
-           ArrayItemVector* static_values,
+           EncodedArrayItem* static_values,
            ClassData* class_data)
       : class_type_(class_type),
         access_flags_(access_flags),
         superclass_(superclass),
         interfaces_(interfaces),
-        interfaces_offset_(interfaces_offset),
         source_file_(source_file),
         annotations_(annotations),
         static_values_(static_values),
-        class_data_(class_data) { }
+        class_data_(class_data) { size_ = kClassDefItemSize; }
 
   ~ClassDef() OVERRIDE { }
 
+  static size_t ItemSize() { return kClassDefItemSize; }
+
   const TypeId* ClassType() const { return class_type_; }
   uint32_t GetAccessFlags() const { return access_flags_; }
   const TypeId* Superclass() const { return superclass_; }
-  TypeIdVector* Interfaces() { return interfaces_.get(); }
-  uint32_t InterfacesOffset() const { return interfaces_offset_; }
-  void SetInterfacesOffset(uint32_t new_offset) { interfaces_offset_ = new_offset; }
+  const TypeIdVector* Interfaces()
+      { return interfaces_ == nullptr ? nullptr: interfaces_->GetTypeList(); }
+  uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); }
   const StringId* SourceFile() const { return source_file_; }
-  AnnotationsDirectoryItem* Annotations() const { return annotations_.get(); }
-  ArrayItemVector* StaticValues() { return static_values_.get(); }
-  ClassData* GetClassData() { return class_data_.get(); }
+  AnnotationsDirectoryItem* Annotations() const { return annotations_; }
+  EncodedArrayItem* StaticValues() { return static_values_; }
+  ClassData* GetClassData() { return class_data_; }
 
   MethodItem* GenerateMethodItem(Header& header, ClassDataItemIterator& cdii);
 
@@ -487,12 +706,12 @@
   const TypeId* class_type_;
   uint32_t access_flags_;
   const TypeId* superclass_;
-  std::unique_ptr<TypeIdVector> interfaces_;
-  uint32_t interfaces_offset_;
+  TypeList* interfaces_;
   const StringId* source_file_;
-  std::unique_ptr<AnnotationsDirectoryItem> annotations_;
-  std::unique_ptr<ArrayItemVector> static_values_;
-  std::unique_ptr<ClassData> class_data_;
+  AnnotationsDirectoryItem* annotations_;
+  EncodedArrayItem* static_values_;
+  ClassData* class_data_;
+
   DISALLOW_COPY_AND_ASSIGN(ClassDef);
 };
 
@@ -506,6 +725,7 @@
  private:
   const TypeId* type_id_;
   uint32_t address_;
+
   DISALLOW_COPY_AND_ASSIGN(CatchHandler);
 };
 
@@ -527,6 +747,7 @@
   uint32_t start_addr_;
   uint16_t insn_count_;
   std::unique_ptr<CatchHandlerVector> handlers_;
+
   DISALLOW_COPY_AND_ASSIGN(TryItem);
 };
 
@@ -555,7 +776,7 @@
   uint16_t InsSize() const { return ins_size_; }
   uint16_t OutsSize() const { return outs_size_; }
   uint16_t TriesSize() const { return tries_ == nullptr ? 0 : tries_->size(); }
-  DebugInfoItem* DebugInfo() const { return debug_info_.get(); }
+  DebugInfoItem* DebugInfo() const { return debug_info_; }
   uint32_t InsnsSize() const { return insns_size_; }
   uint16_t* Insns() const { return insns_.get(); }
   TryItemVector* Tries() const { return tries_.get(); }
@@ -566,14 +787,14 @@
   uint16_t registers_size_;
   uint16_t ins_size_;
   uint16_t outs_size_;
-  std::unique_ptr<DebugInfoItem> debug_info_;
+  DebugInfoItem* debug_info_;
   uint32_t insns_size_;
   std::unique_ptr<uint16_t[]> insns_;
   std::unique_ptr<TryItemVector> tries_;
+
   DISALLOW_COPY_AND_ASSIGN(CodeItem);
 };
 
-
 struct PositionInfo {
   PositionInfo(uint32_t address, uint32_t line) : address_(address), line_(line) { }
 
@@ -617,39 +838,60 @@
  private:
   PositionInfoVector positions_;
   LocalInfoVector locals_;
+
   DISALLOW_COPY_AND_ASSIGN(DebugInfoItem);
 };
 
-class AnnotationItem {
+class AnnotationItem : public Item {
  public:
-  AnnotationItem(uint8_t visibility, ArrayItem* item) : visibility_(visibility), item_(item) { }
+  AnnotationItem(uint8_t visibility, EncodedAnnotation* annotation)
+      : visibility_(visibility), annotation_(annotation) { }
 
   uint8_t GetVisibility() const { return visibility_; }
-  ArrayItem* GetItem() const { return item_.get(); }
-
- private:
-  uint8_t visibility_;
-  std::unique_ptr<ArrayItem> item_;
-  DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
-};
-
-using AnnotationItemVector = std::vector<std::unique_ptr<AnnotationItem>>;
-
-class AnnotationSetItem : public Item {
- public:
-  explicit AnnotationSetItem(AnnotationItemVector* items) : items_(items) { }
-  ~AnnotationSetItem() OVERRIDE { }
-
-  AnnotationItemVector* GetItems() { return items_.get(); }
+  EncodedAnnotation* GetAnnotation() const { return annotation_.get(); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  std::unique_ptr<AnnotationItemVector> items_;
+  uint8_t visibility_;
+  std::unique_ptr<EncodedAnnotation> annotation_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
+};
+
+class AnnotationSetItem : public Item {
+ public:
+  explicit AnnotationSetItem(std::vector<AnnotationItem*>* items) : items_(items) {
+    size_ = sizeof(uint32_t) + items->size() * sizeof(uint32_t);
+  }
+  ~AnnotationSetItem() OVERRIDE { }
+
+  std::vector<AnnotationItem*>* GetItems() { return items_.get(); }
+
+  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+
+ private:
+  std::unique_ptr<std::vector<AnnotationItem*>> items_;
+
   DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem);
 };
 
-using AnnotationSetItemVector = std::vector<std::unique_ptr<AnnotationSetItem>>;
+class AnnotationSetRefList : public Item {
+ public:
+  explicit AnnotationSetRefList(std::vector<AnnotationSetItem*>* items) : items_(items) {
+    size_ = sizeof(uint32_t) + items->size() * sizeof(uint32_t);
+  }
+  ~AnnotationSetRefList() OVERRIDE { }
+
+  std::vector<AnnotationSetItem*>* GetItems() { return items_.get(); }
+
+  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+
+ private:
+  std::unique_ptr<std::vector<AnnotationSetItem*>> items_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList);
+};
 
 class FieldAnnotation {
  public:
@@ -657,11 +899,12 @@
       : field_id_(field_id), annotation_set_item_(annotation_set_item) { }
 
   FieldId* GetFieldId() const { return field_id_; }
-  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
+  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_; }
 
  private:
   FieldId* field_id_;
-  std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+  AnnotationSetItem* annotation_set_item_;
+
   DISALLOW_COPY_AND_ASSIGN(FieldAnnotation);
 };
 
@@ -673,11 +916,12 @@
       : method_id_(method_id), annotation_set_item_(annotation_set_item) { }
 
   MethodId* GetMethodId() const { return method_id_; }
-  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
+  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_; }
 
  private:
   MethodId* method_id_;
-  std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+  AnnotationSetItem* annotation_set_item_;
+
   DISALLOW_COPY_AND_ASSIGN(MethodAnnotation);
 };
 
@@ -685,15 +929,16 @@
 
 class ParameterAnnotation {
  public:
-  ParameterAnnotation(MethodId* method_id, AnnotationSetItemVector* annotations)
+  ParameterAnnotation(MethodId* method_id, AnnotationSetRefList* annotations)
       : method_id_(method_id), annotations_(annotations) { }
 
   MethodId* GetMethodId() const { return method_id_; }
-  AnnotationSetItemVector* GetAnnotations() { return annotations_.get(); }
+  AnnotationSetRefList* GetAnnotations() { return annotations_; }
 
  private:
   MethodId* method_id_;
-  std::unique_ptr<AnnotationSetItemVector> annotations_;
+  AnnotationSetRefList* annotations_;
+
   DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation);
 };
 
@@ -710,7 +955,7 @@
         method_annotations_(method_annotations),
         parameter_annotations_(parameter_annotations) { }
 
-  AnnotationSetItem* GetClassAnnotation() const { return class_annotation_.get(); }
+  AnnotationSetItem* GetClassAnnotation() const { return class_annotation_; }
   FieldAnnotationVector* GetFieldAnnotations() { return field_annotations_.get(); }
   MethodAnnotationVector* GetMethodAnnotations() { return method_annotations_.get(); }
   ParameterAnnotationVector* GetParameterAnnotations() { return parameter_annotations_.get(); }
@@ -718,10 +963,11 @@
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  std::unique_ptr<AnnotationSetItem> class_annotation_;
+  AnnotationSetItem* class_annotation_;
   std::unique_ptr<FieldAnnotationVector> field_annotations_;
   std::unique_ptr<MethodAnnotationVector> method_annotations_;
   std::unique_ptr<ParameterAnnotationVector> parameter_annotations_;
+
   DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem);
 };
 
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 30f57d9..e6868d7 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -24,401 +24,6 @@
 namespace art {
 namespace dex_ir {
 
-namespace {
-
-static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
-  uint64_t value = 0;
-  for (uint32_t i = 0; i <= length; i++) {
-    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
-  }
-  if (sign_extend) {
-    int shift = (7 - length) * 8;
-    return (static_cast<int64_t>(value) << shift) >> shift;
-  }
-  return value;
-}
-
-// Prototype to break cyclic dependency.
-void ReadArrayItemVariant(Header& header,
-                          const uint8_t** data,
-                          uint8_t type,
-                          uint8_t length,
-                          ArrayItem::ArrayItemVariant* item);
-
-ArrayItem* ReadArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
-  ArrayItem* item = new ArrayItem(type);
-  ReadArrayItemVariant(header, data, type, length, item->GetArrayItemVariant());
-  return item;
-}
-
-ArrayItem* ReadArrayItem(Header& header, const uint8_t** data) {
-  const uint8_t encoded_value = *(*data)++;
-  const uint8_t type = encoded_value & 0x1f;
-  ArrayItem* item = new ArrayItem(type);
-  ReadArrayItemVariant(header, data, type, encoded_value >> 5, item->GetArrayItemVariant());
-  return item;
-}
-
-void ReadArrayItemVariant(Header& header,
-                          const uint8_t** data,
-                          uint8_t type,
-                          uint8_t length,
-                          ArrayItem::ArrayItemVariant* item) {
-  switch (type) {
-    case DexFile::kDexAnnotationByte:
-      item->u_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false));
-      break;
-    case DexFile::kDexAnnotationShort:
-      item->u_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationChar:
-      item->u_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false));
-      break;
-    case DexFile::kDexAnnotationInt:
-      item->u_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationLong:
-      item->u_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationFloat: {
-      // Fill on right.
-      union {
-        float f;
-        uint32_t data;
-      } conv;
-      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
-      item->u_.float_val_ = conv.f;
-      break;
-    }
-    case DexFile::kDexAnnotationDouble: {
-      // Fill on right.
-      union {
-        double d;
-        uint64_t data;
-      } conv;
-      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
-      item->u_.double_val_ = conv.d;
-      break;
-    }
-    case DexFile::kDexAnnotationString: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->u_.string_val_ = header.StringIds()[string_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationType: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->u_.string_val_ = header.TypeIds()[string_index]->GetStringId();
-      break;
-    }
-    case DexFile::kDexAnnotationField:
-    case DexFile::kDexAnnotationEnum: {
-      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->u_.field_val_ = header.FieldIds()[field_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationMethod: {
-      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item->u_.method_val_ = header.MethodIds()[method_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationArray: {
-      item->annotation_array_val_.reset(new ArrayItemVector());
-      // Decode all elements.
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      for (uint32_t i = 0; i < size; i++) {
-        item->annotation_array_val_->push_back(
-            std::unique_ptr<ArrayItem>(ReadArrayItem(header, data)));
-      }
-      break;
-    }
-    case DexFile::kDexAnnotationAnnotation: {
-      const uint32_t type_idx = DecodeUnsignedLeb128(data);
-      item->annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId();
-      item->annotation_annotation_val_.array_.reset(
-          new std::vector<std::unique_ptr<ArrayItem::NameValuePair>>());
-      // Decode all name=value pairs.
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      for (uint32_t i = 0; i < size; i++) {
-        const uint32_t name_index = DecodeUnsignedLeb128(data);
-        item->annotation_annotation_val_.array_->push_back(
-            std::unique_ptr<ArrayItem::NameValuePair>(
-                new ArrayItem::NameValuePair(header.StringIds()[name_index].get(),
-                                             ReadArrayItem(header, data))));
-      }
-      break;
-    }
-    case DexFile::kDexAnnotationNull:
-      break;
-    case DexFile::kDexAnnotationBoolean:
-      item->u_.bool_val_ = (length != 0);
-      break;
-    default:
-      break;
-  }
-}
-
-static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  PositionInfoVector& positions = debug_info->GetPositionInfo();
-  positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
-  return false;
-}
-
-static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  LocalInfoVector& locals = debug_info->GetLocalInfo();
-  const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
-  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
-  locals.push_back(std::unique_ptr<LocalInfo>(
-      new LocalInfo(name, entry.descriptor_, signature, entry.start_address_,
-                    entry.end_address_, entry.reg_)));
-}
-
-CodeItem* ReadCodeItem(const DexFile& dex_file,
-                       const DexFile::CodeItem& disk_code_item,
-                       Header& header) {
-  uint16_t registers_size = disk_code_item.registers_size_;
-  uint16_t ins_size = disk_code_item.ins_size_;
-  uint16_t outs_size = disk_code_item.outs_size_;
-  uint32_t tries_size = disk_code_item.tries_size_;
-
-  const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
-  DebugInfoItem* debug_info = nullptr;
-  if (debug_info_stream != nullptr) {
-    debug_info = new DebugInfoItem();
-  }
-
-  uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
-  uint16_t* insns = new uint16_t[insns_size];
-  memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
-
-  TryItemVector* tries = nullptr;
-  if (tries_size > 0) {
-    tries = new TryItemVector();
-    for (uint32_t i = 0; i < tries_size; ++i) {
-      const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
-      uint32_t start_addr = disk_try_item->start_addr_;
-      uint16_t insn_count = disk_try_item->insn_count_;
-      CatchHandlerVector* handlers = new CatchHandlerVector();
-      for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
-        const uint16_t type_index = it.GetHandlerTypeIndex();
-        const TypeId* type_id = header.GetTypeIdOrNullPtr(type_index);
-        handlers->push_back(std::unique_ptr<const CatchHandler>(
-            new CatchHandler(type_id, it.GetHandlerAddress())));
-      }
-      TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
-      tries->push_back(std::unique_ptr<const TryItem>(try_item));
-    }
-  }
-  return new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries);
-}
-
-MethodItem* GenerateMethodItem(const DexFile& dex_file,
-                               dex_ir::Header& header,
-                               ClassDataItemIterator& cdii) {
-  MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get();
-  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
-  CodeItem* code_item = nullptr;
-  DebugInfoItem* debug_info = nullptr;
-  if (disk_code_item != nullptr) {
-    code_item = ReadCodeItem(dex_file, *disk_code_item, header);
-    code_item->SetOffset(cdii.GetMethodCodeItemOffset());
-    debug_info = code_item->DebugInfo();
-  }
-  if (debug_info != nullptr) {
-    bool is_static = (access_flags & kAccStatic) != 0;
-    dex_file.DecodeDebugLocalInfo(
-        disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
-    dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
-  }
-  return new MethodItem(access_flags, method_item, code_item);
-}
-
-AnnotationSetItem* ReadAnnotationSetItem(const DexFile& dex_file,
-                                         const DexFile::AnnotationSetItem& disk_annotations_item,
-                                         Header& header) {
-  if (disk_annotations_item.size_ == 0) {
-    return nullptr;
-  }
-  AnnotationItemVector* items = new AnnotationItemVector();
-  for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
-    const DexFile::AnnotationItem* annotation =
-        dex_file.GetAnnotationItem(&disk_annotations_item, i);
-    if (annotation == nullptr) {
-      continue;
-    }
-    uint8_t visibility = annotation->visibility_;
-    const uint8_t* annotation_data = annotation->annotation_;
-    ArrayItem* array_item =
-        ReadArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0);
-    items->push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item)));
-  }
-  return new AnnotationSetItem(items);
-}
-
-ParameterAnnotation* ReadParameterAnnotation(
-    const DexFile& dex_file,
-    MethodId* method_id,
-    const DexFile::AnnotationSetRefList* annotation_set_ref_list,
-    Header& header) {
-  AnnotationSetItemVector* annotations = new AnnotationSetItemVector();
-  for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
-    const DexFile::AnnotationSetItem* annotation_set_item =
-        dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
-    annotations->push_back(std::unique_ptr<AnnotationSetItem>(
-        ReadAnnotationSetItem(dex_file, *annotation_set_item, header)));
-  }
-  return new ParameterAnnotation(method_id, annotations);
-}
-
-AnnotationsDirectoryItem* ReadAnnotationsDirectoryItem(
-    const DexFile& dex_file,
-    const DexFile::AnnotationsDirectoryItem* disk_annotations_item,
-    Header& header) {
-  const DexFile::AnnotationSetItem* class_set_item =
-      dex_file.GetClassAnnotationSet(disk_annotations_item);
-  AnnotationSetItem* class_annotation = nullptr;
-  if (class_set_item != nullptr) {
-    class_annotation = ReadAnnotationSetItem(dex_file, *class_set_item, header);
-  }
-  const DexFile::FieldAnnotationsItem* fields =
-      dex_file.GetFieldAnnotations(disk_annotations_item);
-  FieldAnnotationVector* field_annotations = nullptr;
-  if (fields != nullptr) {
-    field_annotations = new FieldAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
-      FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get();
-      const DexFile::AnnotationSetItem* field_set_item =
-          dex_file.GetFieldAnnotationSetItem(fields[i]);
-      AnnotationSetItem* annotation_set_item =
-          ReadAnnotationSetItem(dex_file, *field_set_item, header);
-      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
-          new FieldAnnotation(field_id, annotation_set_item)));
-    }
-  }
-  const DexFile::MethodAnnotationsItem* methods =
-      dex_file.GetMethodAnnotations(disk_annotations_item);
-  MethodAnnotationVector* method_annotations = nullptr;
-  if (methods != nullptr) {
-    method_annotations = new MethodAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
-      MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get();
-      const DexFile::AnnotationSetItem* method_set_item =
-          dex_file.GetMethodAnnotationSetItem(methods[i]);
-      AnnotationSetItem* annotation_set_item =
-          ReadAnnotationSetItem(dex_file, *method_set_item, header);
-      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
-          new MethodAnnotation(method_id, annotation_set_item)));
-    }
-  }
-  const DexFile::ParameterAnnotationsItem* parameters =
-      dex_file.GetParameterAnnotations(disk_annotations_item);
-  ParameterAnnotationVector* parameter_annotations = nullptr;
-  if (parameters != nullptr) {
-    parameter_annotations = new ParameterAnnotationVector();
-    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
-      MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get();
-      const DexFile::AnnotationSetRefList* list =
-          dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
-      parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
-          ReadParameterAnnotation(dex_file, method_id, list, header)));
-    }
-  }
-
-  return new AnnotationsDirectoryItem(class_annotation,
-                                      field_annotations,
-                                      method_annotations,
-                                      parameter_annotations);
-}
-
-ClassDef* ReadClassDef(const DexFile& dex_file,
-                       const DexFile::ClassDef& disk_class_def,
-                       Header& header) {
-  const TypeId* class_type = header.TypeIds()[disk_class_def.class_idx_].get();
-  uint32_t access_flags = disk_class_def.access_flags_;
-  const TypeId* superclass = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
-
-  TypeIdVector* interfaces = nullptr;
-  const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
-  uint32_t interfaces_offset = disk_class_def.interfaces_off_;
-  if (type_list != nullptr) {
-    interfaces = new TypeIdVector();
-    for (uint32_t index = 0; index < type_list->Size(); ++index) {
-      interfaces->push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get());
-    }
-  }
-  const StringId* source_file = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
-  // Annotations.
-  AnnotationsDirectoryItem* annotations = nullptr;
-  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
-      dex_file.GetAnnotationsDirectory(disk_class_def);
-  if (disk_annotations_directory_item != nullptr) {
-    annotations = ReadAnnotationsDirectoryItem(dex_file, disk_annotations_directory_item, header);
-    annotations->SetOffset(disk_class_def.annotations_off_);
-  }
-  // Static field initializers.
-  ArrayItemVector* static_values = nullptr;
-  const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
-  if (static_data != nullptr) {
-    uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data);
-    if (static_value_count > 0) {
-      static_values = new ArrayItemVector();
-      for (uint32_t i = 0; i < static_value_count; ++i) {
-        static_values->push_back(std::unique_ptr<ArrayItem>(ReadArrayItem(header, &static_data)));
-      }
-    }
-  }
-  // Read the fields and methods defined by the class, resolving the circular reference from those
-  // to classes by setting class at the same time.
-  const uint8_t* encoded_data = dex_file.GetClassData(disk_class_def);
-  ClassData* class_data = nullptr;
-  if (encoded_data != nullptr) {
-    uint32_t offset = disk_class_def.class_data_off_;
-    ClassDataItemIterator cdii(dex_file, encoded_data);
-    // Static fields.
-    FieldItemVector* static_fields = new FieldItemVector();
-    for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) {
-      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
-    }
-    // Instance fields.
-    FieldItemVector* instance_fields = new FieldItemVector();
-    for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) {
-      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      instance_fields->push_back(
-          std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
-    }
-    // Direct methods.
-    MethodItemVector* direct_methods = new MethodItemVector();
-    for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) {
-      direct_methods->push_back(
-          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii)));
-    }
-    // Virtual methods.
-    MethodItemVector* virtual_methods = new MethodItemVector();
-    for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) {
-      virtual_methods->push_back(
-          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii)));
-    }
-    class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
-    class_data->SetOffset(offset);
-  }
-  return new ClassDef(class_type,
-                      access_flags,
-                      superclass,
-                      interfaces,
-                      interfaces_offset,
-                      source_file,
-                      annotations,
-                      static_values,
-                      class_data);
-}
-
-}  // namespace
-
 Header* DexIrBuilder(const DexFile& dex_file) {
   const DexFile::Header& disk_header = dex_file.GetHeader();
   Header* header = new Header(disk_header.magic_,
@@ -431,73 +36,37 @@
                               disk_header.link_off_,
                               disk_header.data_size_,
                               disk_header.data_off_);
+  Collections& collections = header->GetCollections();
   // Walk the rest of the header fields.
   // StringId table.
-  std::vector<std::unique_ptr<StringId>>& string_ids = header->StringIds();
-  header->SetStringIdsOffset(disk_header.string_ids_off_);
+  collections.SetStringIdsOffset(disk_header.string_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
-    const DexFile::StringId& disk_string_id = dex_file.GetStringId(i);
-    StringId* string_id = new StringId(dex_file.GetStringData(disk_string_id));
-    string_id->SetOffset(i);
-    string_ids.push_back(std::unique_ptr<StringId>(string_id));
+    collections.CreateStringId(dex_file, i);
   }
   // TypeId table.
-  std::vector<std::unique_ptr<TypeId>>& type_ids = header->TypeIds();
-  header->SetTypeIdsOffset(disk_header.type_ids_off_);
+  collections.SetTypeIdsOffset(disk_header.type_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
-    const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
-    TypeId* type_id = new TypeId(header->StringIds()[disk_type_id.descriptor_idx_].get());
-    type_id->SetOffset(i);
-    type_ids.push_back(std::unique_ptr<TypeId>(type_id));
+    collections.CreateTypeId(dex_file, i);
   }
   // ProtoId table.
-  std::vector<std::unique_ptr<ProtoId>>& proto_ids = header->ProtoIds();
-  header->SetProtoIdsOffset(disk_header.proto_ids_off_);
+  collections.SetProtoIdsOffset(disk_header.proto_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
-    const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
-    // Build the parameter type vector.
-    TypeIdVector* parameters = new TypeIdVector();
-    DexFileParameterIterator dfpi(dex_file, disk_proto_id);
-    while (dfpi.HasNext()) {
-      parameters->push_back(header->TypeIds()[dfpi.GetTypeIdx()].get());
-      dfpi.Next();
-    }
-    ProtoId* proto_id = new ProtoId(header->StringIds()[disk_proto_id.shorty_idx_].get(),
-                                    header->TypeIds()[disk_proto_id.return_type_idx_].get(),
-                                    parameters);
-    proto_id->SetOffset(i);
-    proto_ids.push_back(std::unique_ptr<ProtoId>(proto_id));
+    collections.CreateProtoId(dex_file, i);
   }
   // FieldId table.
-  std::vector<std::unique_ptr<FieldId>>& field_ids = header->FieldIds();
-  header->SetFieldIdsOffset(disk_header.field_ids_off_);
+  collections.SetFieldIdsOffset(disk_header.field_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
-    const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
-    FieldId* field_id = new FieldId(header->TypeIds()[disk_field_id.class_idx_].get(),
-                                    header->TypeIds()[disk_field_id.type_idx_].get(),
-                                    header->StringIds()[disk_field_id.name_idx_].get());
-    field_id->SetOffset(i);
-    field_ids.push_back(std::unique_ptr<FieldId>(field_id));
+    collections.CreateFieldId(dex_file, i);
   }
   // MethodId table.
-  std::vector<std::unique_ptr<MethodId>>& method_ids = header->MethodIds();
-  header->SetMethodIdsOffset(disk_header.method_ids_off_);
+  collections.SetMethodIdsOffset(disk_header.method_ids_off_);
   for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
-    const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
-    MethodId* method_id = new MethodId(header->TypeIds()[disk_method_id.class_idx_].get(),
-                                       header->ProtoIds()[disk_method_id.proto_idx_].get(),
-                                       header->StringIds()[disk_method_id.name_idx_].get());
-    method_id->SetOffset(i);
-    method_ids.push_back(std::unique_ptr<MethodId>(method_id));
+    collections.CreateMethodId(dex_file, i);
   }
   // ClassDef table.
-  std::vector<std::unique_ptr<ClassDef>>& class_defs = header->ClassDefs();
-  header->SetClassDefsOffset(disk_header.class_defs_off_);
+  collections.SetClassDefsOffset(disk_header.class_defs_off_);
   for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
-    const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
-    ClassDef* class_def = ReadClassDef(dex_file, disk_class_def, *header);
-    class_def->SetOffset(i);
-    class_defs.push_back(std::unique_ptr<ClassDef>(class_def));
+    collections.CreateClassDef(dex_file, i);
   }
 
   return header;
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 3a3f417..6f34a33 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -30,9 +30,11 @@
 #include <sstream>
 #include <vector>
 
+#include "base/unix_file/fd_file.h"
 #include "dex_ir_builder.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
+#include "os.h"
 #include "utils.h"
 
 namespace art {
@@ -348,10 +350,26 @@
   }  // for
 }
 
+// Forward declare to resolve circular dependence.
+static void DumpEncodedValue(const dex_ir::EncodedValue* data);
+
+/*
+ * Dumps encoded annotation.
+ */
+static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
+  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
+  // Display all name=value pairs.
+  for (auto& subannotation : *annotation->GetAnnotationElements()) {
+    fputc(' ', out_file_);
+    fputs(subannotation->GetName()->Data(), out_file_);
+    fputc('=', out_file_);
+    DumpEncodedValue(subannotation->GetValue());
+  }
+}
 /*
  * Dumps encoded value.
  */
-static void DumpEncodedValue(const dex_ir::ArrayItem* data) {
+static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
   switch (data->Type()) {
     case DexFile::kDexAnnotationByte:
       fprintf(out_file_, "%" PRId8, data->GetByte());
@@ -386,8 +404,8 @@
       break;
     }
     case DexFile::kDexAnnotationType: {
-      dex_ir::StringId* string_id = data->GetStringId();
-      fputs(string_id->Data(), out_file_);
+      dex_ir::TypeId* type_id = data->GetTypeId();
+      fputs(type_id->GetStringId()->Data(), out_file_);
       break;
     }
     case DexFile::kDexAnnotationField:
@@ -404,22 +422,15 @@
     case DexFile::kDexAnnotationArray: {
       fputc('{', out_file_);
       // Display all elements.
-      for (auto& array : *data->GetAnnotationArray()) {
+      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
         fputc(' ', out_file_);
-        DumpEncodedValue(array.get());
+        DumpEncodedValue(value.get());
       }
       fputs(" }", out_file_);
       break;
     }
     case DexFile::kDexAnnotationAnnotation: {
-      fputs(data->GetAnnotationAnnotationString()->Data(), out_file_);
-      // Display all name=value pairs.
-      for (auto& subannotation : *data->GetAnnotationAnnotationNameValuePairArray()) {
-        fputc(' ', out_file_);
-        fputs(subannotation->Name()->Data(), out_file_);
-        fputc('=', out_file_);
-        DumpEncodedValue(subannotation->Value());
-      }
+      DumpEncodedAnnotation(data->GetEncodedAnnotation());
       break;
     }
     case DexFile::kDexAnnotationNull:
@@ -437,8 +448,9 @@
 /*
  * Dumps the file header.
  */
-static void DumpFileHeader(const dex_ir::Header* header) {
+static void DumpFileHeader(dex_ir::Header* header) {
   char sanitized[8 * 2 + 1];
+  dex_ir::Collections& collections = header->GetCollections();
   fprintf(out_file_, "DEX file header:\n");
   Asciify(sanitized, header->Magic(), 8);
   fprintf(out_file_, "magic               : '%s'\n", sanitized);
@@ -452,24 +464,24 @@
   fprintf(out_file_, "link_size           : %d\n", header->LinkSize());
   fprintf(out_file_, "link_off            : %d (0x%06x)\n",
           header->LinkOffset(), header->LinkOffset());
-  fprintf(out_file_, "string_ids_size     : %d\n", header->StringIdsSize());
+  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
   fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
-          header->StringIdsOffset(), header->StringIdsOffset());
-  fprintf(out_file_, "type_ids_size       : %d\n", header->TypeIdsSize());
+          collections.StringIdsOffset(), collections.StringIdsOffset());
+  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
   fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
-          header->TypeIdsOffset(), header->TypeIdsOffset());
-  fprintf(out_file_, "proto_ids_size      : %d\n", header->ProtoIdsSize());
+          collections.TypeIdsOffset(), collections.TypeIdsOffset());
+  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
   fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
-          header->ProtoIdsOffset(), header->ProtoIdsOffset());
-  fprintf(out_file_, "field_ids_size      : %d\n", header->FieldIdsSize());
+          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
+  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
   fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
-          header->FieldIdsOffset(), header->FieldIdsOffset());
-  fprintf(out_file_, "method_ids_size     : %d\n", header->MethodIdsSize());
+          collections.FieldIdsOffset(), collections.FieldIdsOffset());
+  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
   fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
-          header->MethodIdsOffset(), header->MethodIdsOffset());
-  fprintf(out_file_, "class_defs_size     : %d\n", header->ClassDefsSize());
+          collections.MethodIdsOffset(), collections.MethodIdsOffset());
+  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
   fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
-          header->ClassDefsOffset(), header->ClassDefsOffset());
+          collections.ClassDefsOffset(), collections.ClassDefsOffset());
   fprintf(out_file_, "data_size           : %d\n", header->DataSize());
   fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
           header->DataOffset(), header->DataOffset());
@@ -480,19 +492,19 @@
  */
 static void DumpClassDef(dex_ir::Header* header, int idx) {
   // General class information.
-  dex_ir::ClassDef* class_def = header->ClassDefs()[idx].get();
+  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
   fprintf(out_file_, "Class #%d header:\n", idx);
-  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetOffset());
+  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
   fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
           class_def->GetAccessFlags(), class_def->GetAccessFlags());
   uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
-      DexFile::kDexNoIndex16 : class_def->Superclass()->GetOffset();
+      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
   fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
   fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
           class_def->InterfacesOffset(), class_def->InterfacesOffset());
   uint32_t source_file_offset = 0xffffffffU;
   if (class_def->SourceFile() != nullptr) {
-    source_file_offset = class_def->SourceFile()->GetOffset();
+    source_file_offset = class_def->SourceFile()->GetIndex();
   }
   fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
   uint32_t annotations_offset = 0;
@@ -541,7 +553,7 @@
     fputs("  empty-annotation-set\n", out_file_);
     return;
   }
-  for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : *set_item->GetItems()) {
+  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
     if (annotation == nullptr) {
       continue;
     }
@@ -552,10 +564,7 @@
       case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
       default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
     }  // switch
-    // Decode raw bytes in annotation.
-    // const uint8_t* rData = annotation->annotation_;
-    dex_ir::ArrayItem* data = annotation->GetItem();
-    DumpEncodedValue(data);
+    DumpEncodedAnnotation(annotation->GetAnnotation());
     fputc('\n', out_file_);
   }
 }
@@ -564,7 +573,7 @@
  * Dumps class annotations.
  */
 static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
-  dex_ir::ClassDef* class_def = header->ClassDefs()[idx].get();
+  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
   dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
   if (annotations_directory == nullptr) {
     return;  // none
@@ -587,7 +596,7 @@
   if (fields != nullptr) {
     for (auto& field : *fields) {
       const dex_ir::FieldId* field_id = field->GetFieldId();
-      const uint32_t field_idx = field_id->GetOffset();
+      const uint32_t field_idx = field_id->GetIndex();
       const char* field_name = field_id->Name()->Data();
       fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
       DumpAnnotationSetItem(field->GetAnnotationSetItem());
@@ -598,7 +607,7 @@
   if (methods != nullptr) {
     for (auto& method : *methods) {
       const dex_ir::MethodId* method_id = method->GetMethodId();
-      const uint32_t method_idx = method_id->GetOffset();
+      const uint32_t method_idx = method_id->GetIndex();
       const char* method_name = method_id->Name()->Data();
       fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
       DumpAnnotationSetItem(method->GetAnnotationSetItem());
@@ -609,13 +618,13 @@
   if (parameters != nullptr) {
     for (auto& parameter : *parameters) {
       const dex_ir::MethodId* method_id = parameter->GetMethodId();
-      const uint32_t method_idx = method_id->GetOffset();
+      const uint32_t method_idx = method_id->GetIndex();
       const char* method_name = method_id->Name()->Data();
       fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
       uint32_t j = 0;
-      for (auto& annotation : *parameter->GetAnnotations()) {
+      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
         fprintf(out_file_, "#%u\n", j);
-        DumpAnnotationSetItem(annotation.get());
+        DumpAnnotationSetItem(annotation);
         ++j;
       }
     }
@@ -748,24 +757,24 @@
       outSize = snprintf(buf.get(), buf_size, "<no-index>");
       break;
     case Instruction::kIndexTypeRef:
-      if (index < header->TypeIdsSize()) {
-        const char* tp = header->TypeIds()[index]->GetStringId()->Data();
+      if (index < header->GetCollections().TypeIdsSize()) {
+        const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
         outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
       } else {
         outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
       }
       break;
     case Instruction::kIndexStringRef:
-      if (index < header->StringIdsSize()) {
-        const char* st = header->StringIds()[index]->Data();
+      if (index < header->GetCollections().StringIdsSize()) {
+        const char* st = header->GetCollections().GetStringId(index)->Data();
         outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
       } else {
         outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
       }
       break;
     case Instruction::kIndexMethodRef:
-      if (index < header->MethodIdsSize()) {
-        dex_ir::MethodId* method_id = header->MethodIds()[index].get();
+      if (index < header->GetCollections().MethodIdsSize()) {
+        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
         const char* name = method_id->Name()->Data();
         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -776,8 +785,8 @@
       }
       break;
     case Instruction::kIndexFieldRef:
-      if (index < header->FieldIdsSize()) {
-        dex_ir::FieldId* field_id = header->FieldIds()[index].get();
+      if (index < header->GetCollections().FieldIdsSize()) {
+        dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
         const char* name = field_id->Name()->Data();
         const char* type_descriptor = field_id->Type()->GetStringId()->Data();
         const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1028,7 +1037,7 @@
  */
 static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
                           const dex_ir::CodeItem* code, uint32_t code_offset) {
-  dex_ir::MethodId* method_id = header->MethodIds()[idx].get();
+  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
   const char* name = method_id->Name()->Data();
   std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1088,7 +1097,7 @@
     return;
   }
 
-  dex_ir::MethodId* method_id = header->MethodIds()[idx].get();
+  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
   const char* name = method_id->Name()->Data();
   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1187,13 +1196,13 @@
  * Dumps a static (class) field.
  */
 static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
-                       int i, dex_ir::ArrayItem* init) {
+                       int i, dex_ir::EncodedValue* init) {
   // Bail for anything private if export only requested.
   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
   }
 
-  dex_ir::FieldId* field_id = header->FieldIds()[idx].get();
+  dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
   const char* name = field_id->Name()->Data();
   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1293,7 +1302,7 @@
                       dex_ir::Header* header,
                       int idx,
                       char** last_package) {
-  dex_ir::ClassDef* class_def = header->ClassDefs()[idx].get();
+  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
   // Omitting non-public class.
   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
     return;
@@ -1316,7 +1325,8 @@
   // up the classes, sort them, and dump them alphabetically so the
   // package name wouldn't jump around, but that's not a great plan
   // for something that needs to run on the device.
-  const char* class_descriptor = header->ClassDefs()[idx]->ClassType()->GetStringId()->Data();
+  const char* class_descriptor =
+      header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
   if (!(class_descriptor[0] == 'L' &&
         class_descriptor[strlen(class_descriptor)-1] == ';')) {
     // Arrays and primitives should not be defined explicitly. Keep going?
@@ -1386,7 +1396,7 @@
   }
 
   // Interfaces.
-  dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
+  const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
   if (interfaces != nullptr) {
     for (uint32_t i = 0; i < interfaces->size(); i++) {
       DumpInterface((*interfaces)[i], i);
@@ -1396,8 +1406,10 @@
   // Fields and methods.
   dex_ir::ClassData* class_data = class_def->GetClassData();
   // Prepare data for static fields.
-  std::vector<std::unique_ptr<dex_ir::ArrayItem>>* static_values = class_def->StaticValues();
-  const uint32_t static_values_size = (static_values == nullptr) ? 0 : static_values->size();
+  dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
+  dex_ir::EncodedValueVector* encoded_values =
+      static_values == nullptr ? nullptr : static_values->GetEncodedValues();
+  const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
 
   // Static fields.
   if (options_.output_format_ == kOutputPlain) {
@@ -1408,10 +1420,10 @@
     if (static_fields != nullptr) {
       for (uint32_t i = 0; i < static_fields->size(); i++) {
         DumpSField(header,
-                   (*static_fields)[i]->GetFieldId()->GetOffset(),
+                   (*static_fields)[i]->GetFieldId()->GetIndex(),
                    (*static_fields)[i]->GetAccessFlags(),
                    i,
-                   i < static_values_size ? (*static_values)[i].get() : nullptr);
+                   i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
       }  // for
     }
   }
@@ -1425,7 +1437,7 @@
     if (instance_fields != nullptr) {
       for (uint32_t i = 0; i < instance_fields->size(); i++) {
         DumpIField(header,
-                   (*instance_fields)[i]->GetFieldId()->GetOffset(),
+                   (*instance_fields)[i]->GetFieldId()->GetIndex(),
                    (*instance_fields)[i]->GetAccessFlags(),
                    i);
       }  // for
@@ -1441,7 +1453,7 @@
     if (direct_methods != nullptr) {
       for (uint32_t i = 0; i < direct_methods->size(); i++) {
         DumpMethod(header,
-                   (*direct_methods)[i]->GetMethodId()->GetOffset(),
+                   (*direct_methods)[i]->GetMethodId()->GetIndex(),
                    (*direct_methods)[i]->GetAccessFlags(),
                    (*direct_methods)[i]->GetCodeItem(),
                  i);
@@ -1458,7 +1470,7 @@
     if (virtual_methods != nullptr) {
       for (uint32_t i = 0; i < virtual_methods->size(); i++) {
         DumpMethod(header,
-                   (*virtual_methods)[i]->GetMethodId()->GetOffset(),
+                   (*virtual_methods)[i]->GetMethodId()->GetIndex(),
                    (*virtual_methods)[i]->GetAccessFlags(),
                    (*virtual_methods)[i]->GetCodeItem(),
                    i);
@@ -1474,7 +1486,7 @@
     }
     const dex_ir::StringId* source_file = class_def->SourceFile();
     fprintf(out_file_, "  source_file_idx   : %d (%s)\n\n",
-            source_file == nullptr ? 0xffffffffU : source_file->GetOffset(), file_name);
+            source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
   } else if (options_.output_format_ == kOutputXml) {
     fprintf(out_file_, "</class>\n");
   }
@@ -1483,6 +1495,96 @@
 }
 
 /*
+static uint32_t GetDataSectionOffset(dex_ir::Header& header) {
+  return dex_ir::Header::ItemSize() +
+      header.GetCollections().StringIdsSize() * dex_ir::StringId::ItemSize() +
+      header.GetCollections().TypeIdsSize() * dex_ir::TypeId::ItemSize() +
+      header.GetCollections().ProtoIdsSize() * dex_ir::ProtoId::ItemSize() +
+      header.GetCollections().FieldIdsSize() * dex_ir::FieldId::ItemSize() +
+      header.GetCollections().MethodIdsSize() * dex_ir::MethodId::ItemSize() +
+      header.GetCollections().ClassDefsSize() * dex_ir::ClassDef::ItemSize();
+}
+
+static bool Align(File* file, uint32_t& offset) {
+  uint8_t zero_buffer[] = { 0, 0, 0 };
+  uint32_t zeroes = (-offset) & 3;
+  if (zeroes > 0) {
+    if (!file->PwriteFully(zero_buffer, zeroes, offset)) {
+      return false;
+    }
+    offset += zeroes;
+  }
+  return true;
+}
+
+static bool WriteStrings(File* dex_file, dex_ir::Header& header,
+                         uint32_t& index_offset, uint32_t& data_offset) {
+  uint32_t index = 0;
+  uint32_t index_buffer[1];
+  uint32_t string_length;
+  uint32_t length_length;
+  uint8_t length_buffer[8];
+  for (std::unique_ptr<dex_ir::StringId>& string_id : header.GetCollections().StringIds()) {
+    string_id->SetOffset(index);
+    index_buffer[0] = data_offset;
+    string_length = strlen(string_id->Data());
+    length_length = UnsignedLeb128Size(string_length);
+    EncodeUnsignedLeb128(length_buffer, string_length);
+
+    if (!dex_file->PwriteFully(index_buffer, 4, index_offset) ||
+        !dex_file->PwriteFully(length_buffer, length_length, data_offset) ||
+        !dex_file->PwriteFully(string_id->Data(), string_length, data_offset + length_length)) {
+      return false;
+    }
+
+    index++;
+    index_offset += 4;
+    data_offset += string_length + length_length;
+  }
+  return true;
+}
+
+static bool WriteTypes(File* dex_file, dex_ir::Header& header, uint32_t& index_offset) {
+  uint32_t index = 0;
+  uint32_t index_buffer[1];
+  for (std::unique_ptr<dex_ir::TypeId>& type_id : header.GetCollections().TypeIds()) {
+    type_id->SetIndex(index);
+    index_buffer[0] = type_id->GetStringId()->GetOffset();
+
+    if (!dex_file->PwriteFully(index_buffer, 4, index_offset)) {
+      return false;
+    }
+
+    index++;
+    index_offset += 4;
+  }
+  return true;
+}
+
+static bool WriteTypeLists(File* dex_file, dex_ir::Header& header, uint32_t& data_offset) {
+  if (!Align(dex_file, data_offset)) {
+    return false;
+  }
+
+  return true;
+}
+
+static void OutputDexFile(dex_ir::Header& header, const char* file_name) {
+  LOG(INFO) << "FILE NAME: " << file_name;
+  std::unique_ptr<File> dex_file(OS::CreateEmptyFileWriteOnly(file_name));
+  if (dex_file == nullptr) {
+    fprintf(stderr, "Can't open %s\n", file_name);
+    return;
+  }
+
+  uint32_t index_offset = dex_ir::Header::ItemSize();
+  uint32_t data_offset = GetDataSectionOffset(header);
+  WriteStrings(dex_file.get(), header, index_offset, data_offset);
+  WriteTypes(dex_file.get(), header, index_offset);
+}
+*/
+
+/*
  * Dumps the requested sections of the file.
  */
 static void ProcessDexFile(const char* file_name, const DexFile* dex_file) {
@@ -1504,7 +1606,7 @@
 
   // Iterate over all classes.
   char* package = nullptr;
-  const uint32_t class_defs_size = header->ClassDefsSize();
+  const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
   for (uint32_t i = 0; i < class_defs_size; i++) {
     DumpClass(dex_file, header.get(), i, &package);
   }  // for
@@ -1519,6 +1621,14 @@
   if (options_.output_format_ == kOutputXml) {
     fprintf(out_file_, "</api>\n");
   }
+
+  /*
+  // Output dex file.
+  if (options_.output_dex_files_) {
+    std::string output_dex_filename = dex_file->GetLocation() + ".out";
+    OutputDexFile(*header, output_dex_filename.c_str());
+  }
+  */
 }
 
 /*
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index bae587d..736d230 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -41,6 +41,7 @@
   bool disassemble_;
   bool exports_only_;
   bool ignore_bad_checksum_;
+  bool output_dex_files_;
   bool show_annotations_;
   bool show_cfg_;
   bool show_file_headers_;
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 09fa0ef..ec5edf4 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -38,7 +38,7 @@
  */
 static void Usage(void) {
   fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
-  fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile]"
+  fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-w]"
                   " dexfile...\n\n", kProgramName);
   fprintf(stderr, " -a : display annotations\n");
   fprintf(stderr, " -b : build dex_ir\n");
@@ -51,6 +51,7 @@
   fprintf(stderr, " -i : ignore checksum failures\n");
   fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
   fprintf(stderr, " -o : output file name (defaults to stdout)\n");
+  fprintf(stderr, " -w : output dex files\n");
 }
 
 /*
@@ -68,7 +69,7 @@
 
   // Parse all arguments.
   while (1) {
-    const int ic = getopt(argc, argv, "abcdefghil:o:");
+    const int ic = getopt(argc, argv, "abcdefghil:o:w");
     if (ic < 0) {
       break;  // done
     }
@@ -113,6 +114,9 @@
       case 'o':  // output file
         options_.output_file_name_ = optarg;
         break;
+      case 'w':  // output dex files
+        options_.output_dex_files_ = true;
+        break;
       default:
         want_usage = true;
         break;
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 5240011..1af3660 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -37,8 +37,8 @@
 #include "elf_file_impl.h"
 #include "gc/space/image_space.h"
 #include "image-inl.h"
-#include "mirror/abstract_method.h"
 #include "mirror/dex_cache.h"
+#include "mirror/executable.h"
 #include "mirror/object-inl.h"
 #include "mirror/method.h"
 #include "mirror/reference.h"
@@ -770,8 +770,8 @@
   } else if (object->GetClass() == mirror::Method::StaticClass() ||
              object->GetClass() == mirror::Constructor::StaticClass()) {
     // Need to go update the ArtMethod.
-    auto* dest = down_cast<mirror::AbstractMethod*>(copy);
-    auto* src = down_cast<mirror::AbstractMethod*>(object);
+    auto* dest = down_cast<mirror::Executable*>(copy);
+    auto* src = down_cast<mirror::Executable*>(object);
     dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod()));
   }
 }
diff --git a/profman/profman.cc b/profman/profman.cc
index a5fefa7..7722e80 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -280,18 +280,11 @@
     for (size_t i = 0; i < dex_locations_.size(); ++i) {
       std::string error_msg;
       std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
-      std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(apks_fd_[i],
-                                                                     dex_locations_[i].c_str(),
-                                                                     &error_msg));
-      if (zip_archive == nullptr) {
-        LOG(WARNING) << "OpenFromFd failed for '" << dex_locations_[i] << "' " << error_msg;
-        continue;
-      }
-      if (DexFile::OpenFromZip(*zip_archive,
-                               dex_locations_[i],
-                               kVerifyChecksum,
-                               &error_msg,
-                               &dex_files_for_location)) {
+      if (DexFile::OpenZip(apks_fd_[i],
+                           dex_locations_[i],
+                           kVerifyChecksum,
+                           &error_msg,
+                           &dex_files_for_location)) {
       } else {
         LOG(WARNING) << "OpenFromZip failed for '" << dex_locations_[i] << "' " << error_msg;
         continue;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 8c17653..6234a84 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -120,10 +120,10 @@
         "linear_alloc.cc",
         "mem_map.cc",
         "memory_region.cc",
-        "mirror/abstract_method.cc",
         "mirror/array.cc",
         "mirror/class.cc",
         "mirror/dex_cache.cc",
+        "mirror/executable.cc",
         "mirror/field.cc",
         "mirror/method.cc",
         "mirror/object.cc",
@@ -151,9 +151,9 @@
         "native/java_lang_VMClassLoader.cc",
         "native/java_lang_ref_FinalizerReference.cc",
         "native/java_lang_ref_Reference.cc",
-        "native/java_lang_reflect_AbstractMethod.cc",
         "native/java_lang_reflect_Array.cc",
         "native/java_lang_reflect_Constructor.cc",
+        "native/java_lang_reflect_Executable.cc",
         "native/java_lang_reflect_Field.cc",
         "native/java_lang_reflect_Method.cc",
         "native/java_lang_reflect_Parameter.cc",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 0b04480..5d53062 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -272,6 +272,15 @@
 END \c_name
 .endm
 
+.macro NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING c_name, cxx_name
+    .extern \cxx_name
+ENTRY \c_name
+    SETUP_SAVE_EVERYTHING_FRAME r0  @ save all registers as basis for long jump context
+    mov r0, r9                      @ pass Thread::Current
+    bl  \cxx_name                   @ \cxx_name(Thread*)
+END \c_name
+.endm
+
 .macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
@@ -281,10 +290,10 @@
 END \c_name
 .endm
 
-.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+.macro TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r2       @ save all registers as basis for long jump context
+    SETUP_SAVE_EVERYTHING_FRAME r2  @ save all registers as basis for long jump context
     mov r2, r9                      @ pass Thread::Current
     bl  \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
@@ -361,7 +370,7 @@
     /*
      * Called by managed code to create and deliver a NullPointerException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
 
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
@@ -398,19 +407,19 @@
     /*
      * Called by managed code to create and deliver an ArithmeticException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_div_zero, artThrowDivZeroFromCode
 
     /*
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StringIndexOutOfBoundsException
      * as if thrown from a call to String.charAt(). Arg1 holds index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_string_bounds, artThrowStringBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_string_bounds, artThrowStringBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StackOverflowError.
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index e9d03d7..eee949d 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -434,6 +434,17 @@
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
     mov x0, xSELF                     // pass Thread::Current
     bl  \cxx_name                     // \cxx_name(Thread*)
+    brk 0
+END \c_name
+.endm
+
+.macro NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING c_name, cxx_name
+    .extern \cxx_name
+ENTRY \c_name
+    SETUP_SAVE_EVERYTHING_FRAME       // save all registers as basis for long jump context
+    mov x0, xSELF                     // pass Thread::Current
+    bl  \cxx_name                     // \cxx_name(Thread*)
+    brk 0
 END \c_name
 .endm
 
@@ -447,10 +458,10 @@
 END \c_name
 .endm
 
-.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+.macro TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
+    SETUP_SAVE_EVERYTHING_FRAME       // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
     bl  \cxx_name                     // \cxx_name(arg1, arg2, Thread*)
     brk 0
@@ -466,7 +477,7 @@
     /*
      * Called by managed code to create and deliver a NullPointerException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
 
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
@@ -490,19 +501,19 @@
     /*
      * Called by managed code to create and deliver an ArithmeticException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_div_zero, artThrowDivZeroFromCode
 
     /*
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StringIndexOutOfBoundsException
      * as if thrown from a call to String.charAt(). Arg1 holds index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_string_bounds, artThrowStringBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_string_bounds, artThrowStringBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StackOverflowError.
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index 7955b1d..948b06c 100644
--- a/runtime/arch/mips/asm_support_mips.S
+++ b/runtime/arch/mips/asm_support_mips.S
@@ -26,22 +26,6 @@
 // Register holding Thread::Current().
 #define rSELF $s1
 
-     // Declare a function called name, sets up $gp.
-.macro ENTRY name
-    .type \name, %function
-    .global \name
-    // Cache alignment for function entry.
-    .balign 16
-\name:
-    .cfi_startproc
-     // Ensure we get a sane starting CFA.
-    .cfi_def_cfa $sp,0
-    // Load $gp. We expect that ".set noreorder" is in effect.
-    .cpload $t9
-    // Declare a local convenience label to be branched to when $gp is already set up.
-.L\name\()_gp_set:
-.endm
-
      // Declare a function called name, doesn't set up $gp.
 .macro ENTRY_NO_GP_CUSTOM_CFA name, cfa_offset
     .type \name, %function
@@ -59,6 +43,15 @@
     ENTRY_NO_GP_CUSTOM_CFA \name, 0
 .endm
 
+     // Declare a function called name, sets up $gp.
+.macro ENTRY name
+    ENTRY_NO_GP \name
+    // Load $gp. We expect that ".set noreorder" is in effect.
+    .cpload $t9
+    // Declare a local convenience label to be branched to when $gp is already set up.
+.L\name\()_gp_set:
+.endm
+
 .macro END name
     .cfi_endproc
     .size \name, .-\name
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index b6a63ca..1792f31 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -90,7 +90,7 @@
 
   sc->sc_regs[mips::RA] = sc->sc_pc + 4;      // RA needs to point to gc map location
   sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
-  sc->sc_regs[mips::T9] = sc->sc_pc;          // make sure T9 points to the function
+  // Note: This entrypoint does not rely on T9 pointing to it, so we may as well preserve T9.
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 4563004..c3c1882 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -710,8 +710,10 @@
      * Called by managed code to create and deliver a NullPointerException
      */
     .extern artThrowNullPointerExceptionFromCode
-ENTRY art_quick_throw_null_pointer_exception
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_null_pointer_exception
+    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
+    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
+    SETUP_SAVE_EVERYTHING_FRAME
     la   $t9, artThrowNullPointerExceptionFromCode
     jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
     move $a0, rSELF                 # pass Thread::Current
@@ -735,8 +737,8 @@
      * Called by managed code to create and deliver an ArithmeticException
      */
     .extern artThrowDivZeroFromCode
-ENTRY art_quick_throw_div_zero
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_div_zero
+    SETUP_SAVE_EVERYTHING_FRAME
     la   $t9, artThrowDivZeroFromCode
     jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
     move $a0, rSELF                 # pass Thread::Current
@@ -746,8 +748,10 @@
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
      */
     .extern artThrowArrayBoundsFromCode
-ENTRY art_quick_throw_array_bounds
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_array_bounds
+    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
+    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
+    SETUP_SAVE_EVERYTHING_FRAME
     la   $t9, artThrowArrayBoundsFromCode
     jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
     move $a2, rSELF                 # pass Thread::Current
@@ -758,8 +762,8 @@
      * as if thrown from a call to String.charAt().
      */
     .extern artThrowStringBoundsFromCode
-ENTRY art_quick_throw_string_bounds
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_string_bounds
+    SETUP_SAVE_EVERYTHING_FRAME
     la   $t9, artThrowStringBoundsFromCode
     jalr $zero, $t9                 # artThrowStringBoundsFromCode(index, limit, Thread*)
     move $a2, rSELF                 # pass Thread::Current
@@ -1123,7 +1127,7 @@
      */
     .extern artLockObjectFromCode
 ENTRY art_quick_lock_object
-    beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
+    beqz    $a0, art_quick_throw_null_pointer_exception
     nop
     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
     la      $t9, artLockObjectFromCode
@@ -1133,7 +1137,7 @@
 END art_quick_lock_object
 
 ENTRY art_quick_lock_object_no_inline
-    beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
+    beqz    $a0, art_quick_throw_null_pointer_exception
     nop
     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
     la      $t9, artLockObjectFromCode
@@ -1147,7 +1151,7 @@
      */
     .extern artUnlockObjectFromCode
 ENTRY art_quick_unlock_object
-    beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
+    beqz    $a0, art_quick_throw_null_pointer_exception
     nop
     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
     la      $t9, artUnlockObjectFromCode
@@ -1157,7 +1161,7 @@
 END art_quick_unlock_object
 
 ENTRY art_quick_unlock_object_no_inline
-    beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
+    beqz    $a0, art_quick_throw_null_pointer_exception
     nop
     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
     la      $t9, artUnlockObjectFromCode
@@ -1280,7 +1284,7 @@
 ENTRY art_quick_aput_obj_with_null_and_bound_check
     bnez    $a0, .Lart_quick_aput_obj_with_bound_check_gp_set
     nop
-    b .Lart_quick_throw_null_pointer_exception_gp_set
+    b art_quick_throw_null_pointer_exception
     nop
 END art_quick_aput_obj_with_null_and_bound_check
 
@@ -1290,7 +1294,7 @@
     bnez $t1, .Lart_quick_aput_obj_gp_set
     nop
     move $a0, $a1
-    b .Lart_quick_throw_array_bounds_gp_set
+    b art_quick_throw_array_bounds
     move $a1, $t0
 END art_quick_aput_obj_with_bound_check
 
diff --git a/runtime/arch/mips64/asm_support_mips64.S b/runtime/arch/mips64/asm_support_mips64.S
index 6c58fcf..35f20fb 100644
--- a/runtime/arch/mips64/asm_support_mips64.S
+++ b/runtime/arch/mips64/asm_support_mips64.S
@@ -27,24 +27,6 @@
 #define rSELF $s1
 
 
-    // Declare a function called name, sets up $gp.
-    // This macro modifies t8.
-.macro ENTRY name
-    .type \name, %function
-    .global \name
-    // Cache alignment for function entry.
-    .balign 16
-\name:
-    .cfi_startproc
-    // Set up $gp and store the previous $gp value to $t8. It will be pushed to the
-    // stack after the frame has been constructed.
-    .cpsetup $t9, $t8, \name
-    // Ensure we get a sane starting CFA.
-    .cfi_def_cfa $sp,0
-    // Declare a local convenience label to be branched to when $gp is already set up.
-.L\name\()_gp_set:
-.endm
-
     // Declare a function called name, doesn't set up $gp.
 .macro ENTRY_NO_GP_CUSTOM_CFA name, cfa_offset
     .type \name, %function
@@ -62,6 +44,17 @@
     ENTRY_NO_GP_CUSTOM_CFA \name, 0
 .endm
 
+    // Declare a function called name, sets up $gp.
+    // This macro modifies t8.
+.macro ENTRY name
+    ENTRY_NO_GP \name
+    // Set up $gp and store the previous $gp value to $t8. It will be pushed to the
+    // stack after the frame has been constructed.
+    .cpsetup $t9, $t8, \name
+    // Declare a local convenience label to be branched to when $gp is already set up.
+.L\name\()_gp_set:
+.endm
+
 .macro END name
     .cfi_endproc
     .size \name, .-\name
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index e52dc73..709cab5 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -91,7 +91,7 @@
 
   sc->sc_regs[mips64::RA] = sc->sc_pc + 4;      // RA needs to point to gc map location
   sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
-  sc->sc_regs[mips64::T9] = sc->sc_pc;          // make sure T9 points to the function
+  // Note: This entrypoint does not rely on T9 pointing to it, so we may as well preserve T9.
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index c16e855..8fc7bc3 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -817,9 +817,10 @@
      * Called by managed code to create and deliver a NullPointerException
      */
     .extern artThrowNullPointerExceptionFromCode
-ENTRY art_quick_throw_null_pointer_exception
-.Lart_quick_throw_null_pointer_exception_gp_set:
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_null_pointer_exception
+    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
+    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
+    SETUP_SAVE_EVERYTHING_FRAME
     dla  $t9, artThrowNullPointerExceptionFromCode
     jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
     move $a0, rSELF                 # pass Thread::Current
@@ -842,8 +843,8 @@
      * Called by managed code to create and deliver an ArithmeticException
      */
     .extern artThrowDivZeroFromCode
-ENTRY art_quick_throw_div_zero
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_div_zero
+    SETUP_SAVE_EVERYTHING_FRAME
     dla  $t9, artThrowDivZeroFromCode
     jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
     move $a0, rSELF                 # pass Thread::Current
@@ -854,9 +855,10 @@
      * ArrayIndexOutOfBoundsException
      */
     .extern artThrowArrayBoundsFromCode
-ENTRY art_quick_throw_array_bounds
-.Lart_quick_throw_array_bounds_gp_set:
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_array_bounds
+    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
+    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
+    SETUP_SAVE_EVERYTHING_FRAME
     dla  $t9, artThrowArrayBoundsFromCode
     jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
     move $a2, rSELF                 # pass Thread::Current
@@ -867,9 +869,8 @@
      * as if thrown from a call to String.charAt().
      */
     .extern artThrowStringBoundsFromCode
-ENTRY art_quick_throw_string_bounds
-.Lart_quick_throw_string_bounds_gp_set:
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_throw_string_bounds
+    SETUP_SAVE_EVERYTHING_FRAME
     dla  $t9, artThrowStringBoundsFromCode
     jalr $zero, $t9                 # artThrowStringBoundsFromCode(index, limit, Thread*)
     move $a2, rSELF                 # pass Thread::Current
@@ -1210,18 +1211,20 @@
      * Entry from managed code that calls artLockObjectFromCode, may block for GC.
      */
     .extern artLockObjectFromCode
-ENTRY art_quick_lock_object
-    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
+ENTRY_NO_GP art_quick_lock_object
+    beq     $a0, $zero, art_quick_throw_null_pointer_exception
     nop
+    .cpsetup $t9, $t8, art_quick_lock_object
     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
     jal     artLockObjectFromCode         # (Object* obj, Thread*)
     move    $a1, rSELF                    # pass Thread::Current
     RETURN_IF_ZERO
 END art_quick_lock_object
 
-ENTRY art_quick_lock_object_no_inline
-    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
+ENTRY_NO_GP art_quick_lock_object_no_inline
+    beq     $a0, $zero, art_quick_throw_null_pointer_exception
     nop
+    .cpsetup $t9, $t8, art_quick_lock_object_no_inline
     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
     jal     artLockObjectFromCode         # (Object* obj, Thread*)
     move    $a1, rSELF                    # pass Thread::Current
@@ -1232,18 +1235,20 @@
      * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
      */
     .extern artUnlockObjectFromCode
-ENTRY art_quick_unlock_object
-    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
+ENTRY_NO_GP art_quick_unlock_object
+    beq     $a0, $zero, art_quick_throw_null_pointer_exception
     nop
+    .cpsetup $t9, $t8, art_quick_unlock_object
     SETUP_SAVE_REFS_ONLY_FRAME         # save callee saves in case exception allocation triggers GC
     jal     artUnlockObjectFromCode    # (Object* obj, Thread*)
     move    $a1, rSELF                 # pass Thread::Current
     RETURN_IF_ZERO
 END art_quick_unlock_object
 
-ENTRY art_quick_unlock_object_no_inline
-    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
+ENTRY_NO_GP art_quick_unlock_object_no_inline
+    beq     $a0, $zero, art_quick_throw_null_pointer_exception
     nop
+    .cpsetup $t9, $t8, art_quick_unlock_object_no_inline
     SETUP_SAVE_REFS_ONLY_FRAME         # save callee saves in case exception allocation triggers GC
     jal     artUnlockObjectFromCode    # (Object* obj, Thread*)
     move    $a1, rSELF                 # pass Thread::Current
@@ -1362,7 +1367,7 @@
 ENTRY art_quick_aput_obj_with_null_and_bound_check
     bne    $a0, $zero, .Lart_quick_aput_obj_with_bound_check_gp_set
     nop
-    b .Lart_quick_throw_null_pointer_exception_gp_set
+    b art_quick_throw_null_pointer_exception
     nop
 END art_quick_aput_obj_with_null_and_bound_check
 
@@ -1372,7 +1377,7 @@
     bne  $t1, $zero, .Lart_quick_aput_obj_gp_set
     nop
     move $a0, $a1
-    b .Lart_quick_throw_array_bounds_gp_set
+    b art_quick_throw_array_bounds
     move $a1, $t0
 END art_quick_aput_obj_with_bound_check
 
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index f3793e1..879d496 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -327,6 +327,19 @@
     END_FUNCTION VAR(c_name)
 END_MACRO
 
+MACRO2(NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING, c_name, cxx_name)
+    DEFINE_FUNCTION VAR(c_name)
+    SETUP_SAVE_EVERYTHING_FRAME ebx, ebx       // save all registers as basis for long jump context
+    // Outgoing argument set up
+    subl MACRO_LITERAL(12), %esp               // alignment padding
+    CFI_ADJUST_CFA_OFFSET(12)
+    pushl %fs:THREAD_SELF_OFFSET               // pass Thread::Current()
+    CFI_ADJUST_CFA_OFFSET(4)
+    call CALLVAR(cxx_name)                     // cxx_name(Thread*)
+    UNREACHABLE
+    END_FUNCTION VAR(c_name)
+END_MACRO
+
 MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name)
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx // save all registers as basis for long jump context
@@ -341,9 +354,9 @@
     END_FUNCTION VAR(c_name)
 END_MACRO
 
-MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
+MACRO2(TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name)
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx // save all registers as basis for long jump context
+    SETUP_SAVE_EVERYTHING_FRAME ebx, ebx       // save all registers as basis for long jump context
     // Outgoing argument set up
     PUSH eax                                   // alignment padding
     pushl %fs:THREAD_SELF_OFFSET               // pass Thread::Current()
@@ -358,7 +371,7 @@
     /*
      * Called by managed code to create and deliver a NullPointerException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
 
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
@@ -384,7 +397,7 @@
     /*
      * Called by managed code to create and deliver an ArithmeticException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_div_zero, artThrowDivZeroFromCode
 
     /*
      * Called by managed code to create and deliver a StackOverflowError.
@@ -401,13 +414,13 @@
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StringIndexOutOfBoundsException
      * as if thrown from a call to String.charAt(). Arg1 holds index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_string_bounds, artThrowStringBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_string_bounds, artThrowStringBoundsFromCode
 
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index bfba543..a11e402 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -395,6 +395,16 @@
     END_FUNCTION VAR(c_name)
 END_MACRO
 
+MACRO2(NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING, c_name, cxx_name)
+    DEFINE_FUNCTION VAR(c_name)
+    SETUP_SAVE_EVERYTHING_FRAME        // save all registers as basis for long jump context
+    // Outgoing argument set up
+    movq %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current()
+    call CALLVAR(cxx_name)             // cxx_name(Thread*)
+    UNREACHABLE
+    END_FUNCTION VAR(c_name)
+END_MACRO
+
 MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name)
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME  // save all registers as basis for long jump context
@@ -405,9 +415,9 @@
     END_FUNCTION VAR(c_name)
 END_MACRO
 
-MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
+MACRO2(TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name)
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_EVERYTHING_FRAME        // save all registers as basis for long jump context
     // Outgoing argument set up
     movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
     call CALLVAR(cxx_name)             // cxx_name(Thread*)
@@ -418,7 +428,7 @@
     /*
      * Called by managed code to create and deliver a NullPointerException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
 
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
@@ -440,7 +450,7 @@
     /*
      * Called by managed code to create and deliver an ArithmeticException.
      */
-NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
+NO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_div_zero, artThrowDivZeroFromCode
 
     /*
      * Called by managed code to create and deliver a StackOverflowError.
@@ -457,13 +467,13 @@
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
 
     /*
      * Called by managed code to create and deliver a StringIndexOutOfBoundsException
      * as if thrown from a call to String.charAt(). Arg1 holds index, arg2 holds limit.
      */
-TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_string_bounds, artThrowStringBoundsFromCode
+TWO_ARG_RUNTIME_EXCEPTION_SAVE_EVERYTHING art_quick_throw_string_bounds, artThrowStringBoundsFromCode
 
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index fd6c37a..193bea1 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -34,8 +34,8 @@
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
 #include "jni_internal.h"
-#include "mirror/abstract_method.h"
 #include "mirror/class-inl.h"
+#include "mirror/executable.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
@@ -52,9 +52,9 @@
 
 ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject jlr_method) {
-  auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(jlr_method);
-  DCHECK(abstract_method != nullptr);
-  return abstract_method->GetArtMethod();
+  auto* executable = soa.Decode<mirror::Executable*>(jlr_method);
+  DCHECK(executable != nullptr);
+  return executable->GetArtMethod();
 }
 
 mirror::String* ArtMethod::GetNameAsString(Thread* self) {
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 5e0ee6f..7023081 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -28,7 +28,6 @@
 #include "experimental_flags.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/heap.h"
-#include "mirror/abstract_method.h"
 #include "mirror/accessible_object.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
@@ -697,24 +696,18 @@
 struct ExecutableOffsets : public CheckOffsets<mirror::Executable> {
   ExecutableOffsets() : CheckOffsets<mirror::Executable>(
       false, "Ljava/lang/reflect/Executable;") {
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, access_flags_), "accessFlags");
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, art_method_), "artMethod");
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, declaring_class_), "declaringClass");
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, declaring_class_of_overridden_method_),
+              "declaringClassOfOverriddenMethod");
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, dex_method_index_), "dexMethodIndex");
     addOffset(OFFSETOF_MEMBER(mirror::Executable, has_real_parameter_data_),
               "hasRealParameterData");
     addOffset(OFFSETOF_MEMBER(mirror::Executable, parameters_), "parameters");
   };
 };
 
-struct AbstractMethodOffsets : public CheckOffsets<mirror::AbstractMethod> {
-  AbstractMethodOffsets() : CheckOffsets<mirror::AbstractMethod>(
-      false, "Ljava/lang/reflect/AbstractMethod;") {
-    addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, access_flags_), "accessFlags");
-    addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, art_method_), "artMethod");
-    addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_), "declaringClass");
-    addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_of_overridden_method_),
-              "declaringClassOfOverriddenMethod");
-    addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, dex_method_index_), "dexMethodIndex");
-  };
-};
-
 // C++ fields must exactly match the fields in the Java classes. If this fails,
 // reorder the fields in the C++ class. Managed class fields are ordered by
 // ClassLinker::LinkFields.
@@ -733,7 +726,6 @@
   EXPECT_TRUE(AccessibleObjectOffsets().Check());
   EXPECT_TRUE(FieldOffsets().Check());
   EXPECT_TRUE(ExecutableOffsets().Check());
-  EXPECT_TRUE(AbstractMethodOffsets().Check());
 }
 
 TEST_F(ClassLinkerTest, FindClassNonexistent) {
@@ -1269,7 +1261,6 @@
                                                 old_dex_file->Size(),
                                                 location->ToModifiedUtf8(),
                                                 0u,
-                                                nullptr,
                                                 nullptr));
   {
     WriterMutexLock mu(soa.Self(), *class_linker->DexLock());
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 03223b0..70b7f87 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -52,6 +52,10 @@
 
 namespace art {
 
+static constexpr OatDexFile* kNoOatDexFile = nullptr;
+
+const char* DexFile::kClassesDex = "classes.dex";
+
 const uint8_t DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
 const uint8_t DexFile::kDexMagicVersions[DexFile::kNumDexVersions][DexFile::kDexVersionLen] = {
   {'0', '3', '5', '\0'},
@@ -118,64 +122,6 @@
   return false;
 }
 
-bool DexFile::Open(const char* filename,
-                   const char* location,
-                   bool verify_checksum,
-                   std::string* error_msg,
-                   std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace(std::string("Open dex file ") + 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 DexFile::OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
-  }
-  if (IsDexMagic(magic)) {
-    std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.Release(),
-                                                              location,
-                                                              /* verify */ true,
-                                                              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;
-}
-
-static bool ContainsClassesDex(int fd, const char* filename) {
-  std::string error_msg;
-  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, filename, &error_msg));
-  if (zip_archive.get() == nullptr) {
-    return false;
-  }
-  std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(DexFile::kClassesDex, &error_msg));
-  return (zip_entry.get() != nullptr);
-}
-
-bool DexFile::MaybeDex(const char* filename) {
-  uint32_t magic;
-  std::string error_msg;
-  File fd = OpenAndReadMagic(filename, &magic, &error_msg);
-  if (fd.Fd() == -1) {
-    return false;
-  }
-  if (IsZipMagic(magic)) {
-    return ContainsClassesDex(fd.Release(), filename);
-  } else if (IsDexMagic(magic)) {
-    return true;
-  }
-  return false;
-}
-
 int DexFile::GetPermissions() const {
   if (mem_map_.get() == nullptr) {
     return 0;
@@ -206,7 +152,9 @@
   }
 }
 
-std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base, size_t size,
+
+std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base,
+                                             size_t size,
                                              const std::string& location,
                                              uint32_t location_checksum,
                                              const OatDexFile* oat_dex_file,
@@ -214,118 +162,78 @@
                                              bool verify_checksum,
                                              std::string* error_msg) {
   ScopedTrace trace(std::string("Open dex file from RAM ") + location);
-  std::unique_ptr<const DexFile> dex_file = OpenMemory(base,
-                                                       size,
-                                                       location,
-                                                       location_checksum,
-                                                       nullptr,
-                                                       oat_dex_file,
-                                                       error_msg);
-  if (dex_file == nullptr) {
-    return nullptr;
-  }
-
-  if (verify && !DexFileVerifier::Verify(dex_file.get(),
-                                         dex_file->Begin(),
-                                         dex_file->Size(),
-                                         location.c_str(),
-                                         verify_checksum,
-                                         error_msg)) {
-    return nullptr;
-  }
-  return dex_file;
+  return OpenCommon(base,
+                    size,
+                    location,
+                    location_checksum,
+                    oat_dex_file,
+                    verify,
+                    verify_checksum,
+                    error_msg);
 }
 
 std::unique_ptr<const DexFile> DexFile::Open(const std::string& location,
                                              uint32_t location_checksum,
-                                             std::unique_ptr<MemMap> mem_map,
+                                             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);
-  std::unique_ptr<const DexFile> dex_file = OpenMemory(location,
-                                                       location_checksum,
-                                                       std::move(mem_map),
-                                                       error_msg);
-  if (dex_file == nullptr) {
-    return nullptr;
-  }
-
-  if (verify && !DexFileVerifier::Verify(dex_file.get(),
-                                         dex_file->Begin(),
-                                         dex_file->Size(),
-                                         location.c_str(),
-                                         verify_checksum,
-                                         error_msg)) {
-    return nullptr;
+  CHECK(map.get() != nullptr);
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 location_checksum,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg);
+  if (dex_file != nullptr) {
+    dex_file->mem_map_.reset(map.release());
   }
   return dex_file;
 }
 
-std::unique_ptr<const DexFile> DexFile::OpenFile(int fd,
-                                                 const char* location,
-                                                 bool verify,
-                                                 bool verify_checksum,
-                                                 std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file ") + location);
-  CHECK(location != nullptr);
-  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, strerror(errno));
-      return nullptr;
-    }
-    if (S_ISDIR(sbuf.st_mode)) {
-      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location);
-      return nullptr;
-    }
-    size_t length = sbuf.st_size;
-    map.reset(MemMap::MapFile(length,
-                              PROT_READ,
-                              MAP_PRIVATE,
-                              fd,
-                              0,
-                              /*low_4gb*/false,
-                              location,
-                              error_msg));
-    if (map == nullptr) {
-      DCHECK(!error_msg->empty());
-      return nullptr;
+bool DexFile::Open(const char* filename,
+                   const std::string& location,
+                   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 DexFile::OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
+  }
+  if (IsDexMagic(magic)) {
+    std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.Release(),
+                                                              location,
+                                                              /* verify */ true,
+                                                              verify_checksum,
+                                                              error_msg));
+    if (dex_file.get() != nullptr) {
+      dex_files->push_back(std::move(dex_file));
+      return true;
+    } else {
+      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);
-    return nullptr;
-  }
-
-  const Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
-
-  std::unique_ptr<const DexFile> dex_file(OpenMemory(location,
-                                                     dex_header->checksum_,
-                                                     std::move(map),
-                                                     error_msg));
-  if (dex_file.get() == nullptr) {
-    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location,
-                              error_msg->c_str());
-    return nullptr;
-  }
-
-  if (verify && !DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(),
-                                         location,
-                                         verify_checksum,
-                                         error_msg)) {
-    return nullptr;
-  }
-
-  return dex_file;
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return false;
 }
 
-const char* DexFile::kClassesDex = "classes.dex";
+std::unique_ptr<const DexFile> DexFile::OpenDex(int fd,
+                                                const std::string& location,
+                                                bool verify_checksum,
+                                                std::string* error_msg) {
+  ScopedTrace trace("Open dex file " + std::string(location));
+  return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
+}
 
 bool DexFile::OpenZip(int fd,
                       const std::string& location,
@@ -339,28 +247,79 @@
     DCHECK(!error_msg->empty());
     return false;
   }
-  return DexFile::OpenFromZip(*zip_archive, location, verify_checksum, error_msg, dex_files);
+  return DexFile::OpenAllDexFilesFromZip(*zip_archive,
+                                         location,
+                                         verify_checksum,
+                                         error_msg,
+                                         dex_files);
 }
 
-std::unique_ptr<const DexFile> DexFile::OpenMemory(const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> mem_map,
-                                                   std::string* error_msg) {
-  return OpenMemory(mem_map->Begin(),
-                    mem_map->Size(),
-                    location,
-                    location_checksum,
-                    std::move(mem_map),
-                    nullptr,
-                    error_msg);
+std::unique_ptr<const DexFile> DexFile::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;
+    }
+  }
+
+  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 Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
+
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 dex_header->checksum_,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg);
+  if (dex_file != nullptr) {
+    dex_file->mem_map_.reset(map.release());
+  }
+
+  return dex_file;
 }
 
-std::unique_ptr<const DexFile> DexFile::Open(const ZipArchive& zip_archive,
-                                             const char* entry_name,
-                                             const std::string& location,
-                                             bool verify_checksum,
-                                             std::string* error_msg,
-                                             ZipOpenErrorCode* error_code) {
+std::unique_ptr<const DexFile> DexFile::OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+                                                              const char* entry_name,
+                                                              const std::string& location,
+                                                              bool verify_checksum,
+                                                              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));
@@ -380,15 +339,18 @@
     *error_code = ZipOpenErrorCode::kExtractToMemoryError;
     return nullptr;
   }
-  std::unique_ptr<const DexFile> dex_file(OpenMemory(location,
-                                                     zip_entry->GetCrc32(),
-                                                     std::move(map),
-                                                     error_msg));
-  if (dex_file == nullptr) {
-    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
-                              error_msg->c_str());
-    *error_code = ZipOpenErrorCode::kDexFileError;
-    return nullptr;
+  VerifyResult verify_result;
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 zip_entry->GetCrc32(),
+                                                 kNoOatDexFile,
+                                                 /* verify */ true,
+                                                 verify_checksum,
+                                                 error_msg,
+                                                 &verify_result);
+  if (dex_file != nullptr) {
+    dex_file->mem_map_.reset(map.release());
   }
   if (!dex_file->DisableWrite()) {
     *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
@@ -396,10 +358,7 @@
     return nullptr;
   }
   CHECK(dex_file->IsReadOnly()) << location;
-  if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(),
-                               location.c_str(),
-                               verify_checksum,
-                               error_msg)) {
+  if (verify_result != VerifyResult::kVerifySucceeded) {
     *error_code = ZipOpenErrorCode::kVerifyError;
     return nullptr;
   }
@@ -413,16 +372,20 @@
 // seems an excessive number.
 static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
 
-bool DexFile::OpenFromZip(const ZipArchive& zip_archive,
-                          const std::string& location,
-                          bool verify_checksum,
-                          std::string* error_msg,
-                          std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+bool DexFile::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                                     const std::string& location,
+                                     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(
-      Open(zip_archive, kClassesDex, location, verify_checksum, error_msg, &error_code));
+  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                kClassesDex,
+                                                                location,
+                                                                verify_checksum,
+                                                                error_msg,
+                                                                &error_code));
   if (dex_file.get() == nullptr) {
     return false;
   } else {
@@ -437,8 +400,12 @@
     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(
-          Open(zip_archive, name.c_str(), fake_location, verify_checksum, error_msg, &error_code));
+      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                         name.c_str(),
+                                                                         fake_location,
+                                                                         verify_checksum,
+                                                                         error_msg,
+                                                                         &error_code));
       if (next_dex_file.get() == nullptr) {
         if (error_code != ZipOpenErrorCode::kEntryNotFound) {
           LOG(WARNING) << error_msg;
@@ -464,35 +431,55 @@
   }
 }
 
-
-std::unique_ptr<const DexFile> DexFile::OpenMemory(const uint8_t* base,
-                                                   size_t size,
-                                                   const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> mem_map,
-                                                   const OatDexFile* oat_dex_file,
-                                                   std::string* error_msg) {
-  DCHECK(base != nullptr);
-  DCHECK_NE(size, 0U);
-  CHECK_ALIGNED(base, 4);  // various dex file structures must be word aligned
-  std::unique_ptr<DexFile> dex_file(
-      new DexFile(base, size, location, location_checksum, std::move(mem_map), oat_dex_file));
+std::unique_ptr<DexFile> DexFile::OpenCommon(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,
+                                             VerifyResult* verify_result) {
+  std::unique_ptr<DexFile> dex_file(new DexFile(base,
+                                                size,
+                                                location,
+                                                location_checksum,
+                                                oat_dex_file));
+  if (dex_file == nullptr) {
+    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
+                              error_msg->c_str());
+    return nullptr;
+  }
   if (!dex_file->Init(error_msg)) {
     dex_file.reset();
+    return nullptr;
   }
-  return std::unique_ptr<const DexFile>(dex_file.release());
+  if (verify && !DexFileVerifier::Verify(dex_file.get(),
+                                         dex_file->Begin(),
+                                         dex_file->Size(),
+                                         location.c_str(),
+                                         verify_checksum,
+                                         error_msg)) {
+    if (verify_result != nullptr) {
+      *verify_result = VerifyResult::kVerifyFailed;
+    }
+    return nullptr;
+  }
+  if (verify_result != nullptr) {
+    *verify_result = VerifyResult::kVerifySucceeded;
+  }
+  return dex_file;
 }
 
-DexFile::DexFile(const uint8_t* base, size_t size,
+DexFile::DexFile(const uint8_t* base,
+                 size_t size,
                  const std::string& location,
                  uint32_t location_checksum,
-                 std::unique_ptr<MemMap> mem_map,
                  const OatDexFile* oat_dex_file)
     : begin_(base),
       size_(size),
       location_(location),
       location_checksum_(location_checksum),
-      mem_map_(std::move(mem_map)),
       header_(reinterpret_cast<const Header*>(base)),
       string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)),
       type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)),
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 97c2596..14bde09 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -397,15 +397,9 @@
   // Return true if the checksum could be found, false otherwise.
   static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg);
 
-  // Opens .dex files found in the container, guessing the container format based on file extension.
-  static bool Open(const char* filename,
-                   const char* location,
-                   bool verify_checksum,
-                   std::string* error_msg,
-                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
   // Opens .dex file, backed by existing memory
-  static std::unique_ptr<const DexFile> Open(const uint8_t* base, size_t size,
+  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,
@@ -421,16 +415,25 @@
                                              bool verify_checksum,
                                              std::string* error_msg);
 
-  // Checks whether the given file has the dex magic, or is a zip file with a classes.dex entry.
-  // If this function returns false, Open will not succeed. The inverse is not true, however.
-  static bool MaybeDex(const char* filename);
+  // 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_checksum,
+                   std::string* error_msg,
+                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
 
-  // Open all classesXXX.dex files from a zip archive.
-  static bool OpenFromZip(const ZipArchive& zip_archive,
-                          const std::string& location,
-                          bool verify_checksum,
-                          std::string* error_msg,
-                          std::vector<std::unique_ptr<const DexFile>>* dex_files);
+  // Open a single dex file from an fd.
+  static std::unique_ptr<const DexFile> OpenDex(int fd,
+                                                const std::string& location,
+                                                bool verify_checksum,
+                                                std::string* error_msg);
+
+  // Opens dex files from within a .jar, .zip, or .apk file
+  static bool OpenZip(int fd,
+                      const std::string& location,
+                      bool verify_checksum,
+                      std::string* error_msg,
+                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
 
   // Closes a .dex file.
   virtual ~DexFile();
@@ -1011,20 +1014,12 @@
   static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right);
 
  private:
-  // Opens a .dex file
   static std::unique_ptr<const DexFile> OpenFile(int fd,
-                                                 const char* location,
+                                                 const std::string& location,
                                                  bool verify,
                                                  bool verify_checksum,
                                                  std::string* error_msg);
 
-  // Opens dex files from within a .jar, .zip, or .apk file
-  static bool OpenZip(int fd,
-                      const std::string& location,
-                      bool verify_checksum,
-                      std::string* error_msg,
-                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
   enum class ZipOpenErrorCode {  // private
     kNoError,
     kEntryNotFound,
@@ -1034,34 +1029,41 @@
     kVerifyError
   };
 
+  // Open all classesXXX.dex files from a zip archive.
+  static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                                     const std::string& location,
+                                     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> Open(const ZipArchive& zip_archive,
-                                             const char* entry_name,
+  static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+                                                              const char* entry_name,
+                                                              const std::string& location,
+                                                              bool verify_checksum,
+                                                              std::string* error_msg,
+                                                              ZipOpenErrorCode* error_code);
+
+  enum class VerifyResult {  // private
+    kVerifySucceeded,
+    kVerifyFailed
+  };
+
+  static std::unique_ptr<DexFile> OpenCommon(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,
-                                             ZipOpenErrorCode* error_code);
+                                             VerifyResult* verify_result = nullptr);
 
-  // Opens a .dex file at the given address backed by a MemMap
-  static std::unique_ptr<const DexFile> OpenMemory(const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> mem_map,
-                                                   std::string* error_msg);
-
-  // Opens a .dex file at the given address, optionally backed by a MemMap
-  static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
-                                                   size_t size,
-                                                   const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> mem_map,
-                                                   const OatDexFile* oat_dex_file,
-                                                   std::string* error_msg);
-
-  DexFile(const uint8_t* base, size_t size,
+  DexFile(const uint8_t* base,
+          size_t size,
           const std::string& location,
           uint32_t location_checksum,
-          std::unique_ptr<MemMap> mem_map,
           const OatDexFile* oat_dex_file);
 
   // Top-level initializer that calls other Init methods.
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 71c0ad9..5939ef3 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -123,7 +123,7 @@
 class DexFileVerifierTest : public CommonRuntimeTest {
  protected:
   DexFile* GetDexFile(const uint8_t* dex_bytes, size_t length) {
-    return new DexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr);
+    return new DexFile(dex_bytes, length, "tmp", 0, nullptr);
   }
 
   void VerifyModification(const char* dex_file_base64_content,
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index a434442..d9cb1c6 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -375,7 +375,7 @@
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     ArtMethod* m = soa.DecodeMethod(mid);
-    mirror::AbstractMethod* method;
+    mirror::Executable* method;
     DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
     DCHECK(!Runtime::Current()->IsActiveTransaction());
     if (m->IsConstructor()) {
diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h
deleted file mode 100644
index 9c20613..0000000
--- a/runtime/mirror/abstract_method.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_
-#define ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_
-
-#include "executable.h"
-#include "gc_root.h"
-#include "object.h"
-#include "object_callbacks.h"
-#include "read_barrier_option.h"
-
-namespace art {
-
-struct AbstractMethodOffsets;
-class ArtMethod;
-
-namespace mirror {
-
-// C++ mirror of java.lang.reflect.AbstractMethod.
-class MANAGED AbstractMethod : public Executable {
- public:
-  // Called from Constructor::CreateFromArtMethod, Method::CreateFromArtMethod.
-  template <PointerSize kPointerSize, bool kTransactionActive>
-  bool CreateFromArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
-      REQUIRES(!Roles::uninterruptible_);
-
-  ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_);
-  // Only used by the image writer.
-  template <bool kTransactionActive = false>
-  void SetArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Class* GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
-
- private:
-  static MemberOffset ArtMethodOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, art_method_));
-  }
-  static MemberOffset DeclaringClassOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_));
-  }
-  static MemberOffset DeclaringClassOfOverriddenMethodOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_of_overridden_method_));
-  }
-  static MemberOffset AccessFlagsOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, access_flags_));
-  }
-  static MemberOffset DexMethodIndexOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, dex_method_index_));
-  }
-
-  HeapReference<mirror::Class> declaring_class_;
-  HeapReference<mirror::Class> declaring_class_of_overridden_method_;
-  uint64_t art_method_;
-  uint32_t access_flags_;
-  uint32_t dex_method_index_;
-
-  friend struct art::AbstractMethodOffsets;  // for verifying offset information
-  DISALLOW_IMPLICIT_CONSTRUCTORS(AbstractMethod);
-};
-
-}  // namespace mirror
-}  // namespace art
-
-#endif  // ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_
diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/executable.cc
similarity index 70%
rename from runtime/mirror/abstract_method.cc
rename to runtime/mirror/executable.cc
index b4dce58..33ebd81 100644
--- a/runtime/mirror/abstract_method.cc
+++ b/runtime/mirror/executable.cc
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-#include "abstract_method.h"
-
 #include "art_method-inl.h"
+#include "executable.h"
 
 namespace art {
 namespace mirror {
 
 template <PointerSize kPointerSize, bool kTransactionActive>
-bool AbstractMethod::CreateFromArtMethod(ArtMethod* method) {
+bool Executable::CreateFromArtMethod(ArtMethod* method) {
   auto* interface_method = method->GetInterfaceMethodIfProxy(kPointerSize);
   SetArtMethod<kTransactionActive>(method);
   SetFieldObject<kTransactionActive>(DeclaringClassOffset(), method->GetDeclaringClass());
@@ -33,28 +32,28 @@
   return true;
 }
 
-template bool AbstractMethod::CreateFromArtMethod<PointerSize::k32, false>(
+template bool Executable::CreateFromArtMethod<PointerSize::k32, false>(
     ArtMethod* method);
-template bool AbstractMethod::CreateFromArtMethod<PointerSize::k32, true>(
+template bool Executable::CreateFromArtMethod<PointerSize::k32, true>(
     ArtMethod* method);
-template bool AbstractMethod::CreateFromArtMethod<PointerSize::k64, false>(
+template bool Executable::CreateFromArtMethod<PointerSize::k64, false>(
     ArtMethod* method);
-template bool AbstractMethod::CreateFromArtMethod<PointerSize::k64, true>(
+template bool Executable::CreateFromArtMethod<PointerSize::k64, true>(
     ArtMethod* method);
 
-ArtMethod* AbstractMethod::GetArtMethod() {
+ArtMethod* Executable::GetArtMethod() {
   return reinterpret_cast<ArtMethod*>(GetField64(ArtMethodOffset()));
 }
 
 template <bool kTransactionActive>
-void AbstractMethod::SetArtMethod(ArtMethod* method) {
+void Executable::SetArtMethod(ArtMethod* method) {
   SetField64<kTransactionActive>(ArtMethodOffset(), reinterpret_cast<uint64_t>(method));
 }
 
-template void AbstractMethod::SetArtMethod<false>(ArtMethod* method);
-template void AbstractMethod::SetArtMethod<true>(ArtMethod* method);
+template void Executable::SetArtMethod<false>(ArtMethod* method);
+template void Executable::SetArtMethod<true>(ArtMethod* method);
 
-mirror::Class* AbstractMethod::GetDeclaringClass() {
+mirror::Class* Executable::GetDeclaringClass() {
   return GetFieldObject<mirror::Class>(DeclaringClassOffset());
 }
 
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 232fce8..6c465f6 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -32,9 +32,42 @@
 
 // C++ mirror of java.lang.reflect.Executable.
 class MANAGED Executable : public AccessibleObject {
+ public:
+  // Called from Constructor::CreateFromArtMethod, Method::CreateFromArtMethod.
+  template <PointerSize kPointerSize, bool kTransactionActive>
+  bool CreateFromArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
+
+  ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_);
+  // Only used by the image writer.
+  template <bool kTransactionActive = false>
+  void SetArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
+  mirror::Class* GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   uint16_t has_real_parameter_data_;
+  HeapReference<mirror::Class> declaring_class_;
+  HeapReference<mirror::Class> declaring_class_of_overridden_method_;
   HeapReference<mirror::Array> parameters_;
+  uint64_t art_method_;
+  uint32_t access_flags_;
+  uint32_t dex_method_index_;
+
+  static MemberOffset ArtMethodOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Executable, art_method_));
+  }
+  static MemberOffset DeclaringClassOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Executable, declaring_class_));
+  }
+  static MemberOffset DeclaringClassOfOverriddenMethodOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Executable, declaring_class_of_overridden_method_));
+  }
+  static MemberOffset AccessFlagsOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Executable, access_flags_));
+  }
+  static MemberOffset DexMethodIndexOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Executable, dex_method_index_));
+  }
 
   friend struct art::ExecutableOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(Executable);
diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc
index ef16719..71bac7e 100644
--- a/runtime/mirror/method.cc
+++ b/runtime/mirror/method.cc
@@ -56,7 +56,7 @@
   DCHECK(!method->IsConstructor()) << PrettyMethod(method);
   auto* ret = down_cast<Method*>(StaticClass()->AllocObject(self));
   if (LIKELY(ret != nullptr)) {
-    static_cast<AbstractMethod*>(ret)->
+    static_cast<Executable*>(ret)->
         CreateFromArtMethod<kPointerSize, kTransactionActive>(method);
   }
   return ret;
@@ -108,7 +108,7 @@
   DCHECK(method->IsConstructor()) << PrettyMethod(method);
   auto* ret = down_cast<Constructor*>(StaticClass()->AllocObject(self));
   if (LIKELY(ret != nullptr)) {
-    static_cast<AbstractMethod*>(ret)->
+    static_cast<Executable*>(ret)->
         CreateFromArtMethod<kPointerSize, kTransactionActive>(method);
   }
   return ret;
diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h
index 6881991..205ea7a 100644
--- a/runtime/mirror/method.h
+++ b/runtime/mirror/method.h
@@ -17,8 +17,8 @@
 #ifndef ART_RUNTIME_MIRROR_METHOD_H_
 #define ART_RUNTIME_MIRROR_METHOD_H_
 
-#include "abstract_method.h"
 #include "gc_root.h"
+#include "executable.h"
 
 namespace art {
 namespace mirror {
@@ -26,7 +26,7 @@
 class Class;
 
 // C++ mirror of java.lang.reflect.Method.
-class MANAGED Method : public AbstractMethod {
+class MANAGED Method : public Executable {
  public:
   template <PointerSize kPointerSize, bool kTransactionActive>
   static Method* CreateFromArtMethod(Thread* self, ArtMethod* method)
@@ -58,7 +58,7 @@
 };
 
 // C++ mirror of java.lang.reflect.Constructor.
-class MANAGED Constructor: public AbstractMethod {
+class MANAGED Constructor: public Executable {
  public:
   template <PointerSize kPointerSize, bool kTransactionActive>
   static Constructor* CreateFromArtMethod(Thread* self, ArtMethod* method)
diff --git a/runtime/native/java_lang_reflect_AbstractMethod.cc b/runtime/native/java_lang_reflect_Executable.cc
similarity index 77%
rename from runtime/native/java_lang_reflect_AbstractMethod.cc
rename to runtime/native/java_lang_reflect_Executable.cc
index 254f8db..8fcf6ac 100644
--- a/runtime/native/java_lang_reflect_AbstractMethod.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "java_lang_reflect_AbstractMethod.h"
+#include "java_lang_reflect_Executable.h"
 
 #include "art_method-inl.h"
 #include "dex_file_annotations.h"
@@ -28,7 +28,7 @@
 
 namespace art {
 
-static jobjectArray AbstractMethod_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) {
+static jobjectArray Executable_getDeclaredAnnotationsNative(JNIEnv* env, jobject javaMethod) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
@@ -42,7 +42,7 @@
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
 }
 
-static jobject AbstractMethod_getAnnotationNative(JNIEnv* env,
+static jobject Executable_getAnnotationNative(JNIEnv* env,
                                                   jobject javaMethod,
                                                   jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
@@ -56,7 +56,7 @@
   }
 }
 
-static jobjectArray AbstractMethod_getSignatureAnnotation(JNIEnv* env, jobject javaMethod) {
+static jobjectArray Executable_getSignatureAnnotation(JNIEnv* env, jobject javaMethod) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
@@ -67,7 +67,7 @@
 }
 
 
-static jobjectArray AbstractMethod_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
+static jobjectArray Executable_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->IsProxyMethod()) {
@@ -77,7 +77,7 @@
   }
 }
 
-static jboolean AbstractMethod_isAnnotationPresentNative(JNIEnv* env,
+static jboolean Executable_isAnnotationPresentNative(JNIEnv* env,
                                                          jobject javaMethod,
                                                          jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
@@ -91,17 +91,17 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(AbstractMethod, getAnnotationNative,
+  NATIVE_METHOD(Executable, getAnnotationNative,
                 "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
-  NATIVE_METHOD(AbstractMethod, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
-  NATIVE_METHOD(AbstractMethod, getParameterAnnotationsNative,
+  NATIVE_METHOD(Executable, getDeclaredAnnotationsNative, "!()[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Executable, getParameterAnnotationsNative,
                 "!()[[Ljava/lang/annotation/Annotation;"),
-  NATIVE_METHOD(AbstractMethod, getSignatureAnnotation, "!()[Ljava/lang/String;"),
-  NATIVE_METHOD(AbstractMethod, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
+  NATIVE_METHOD(Executable, getSignatureAnnotation, "!()[Ljava/lang/String;"),
+  NATIVE_METHOD(Executable, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
 };
 
-void register_java_lang_reflect_AbstractMethod(JNIEnv* env) {
-  REGISTER_NATIVE_METHODS("java/lang/reflect/AbstractMethod");
+void register_java_lang_reflect_Executable(JNIEnv* env) {
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Executable");
 }
 
 }  // namespace art
diff --git a/runtime/native/java_lang_reflect_AbstractMethod.h b/runtime/native/java_lang_reflect_Executable.h
similarity index 72%
rename from runtime/native/java_lang_reflect_AbstractMethod.h
rename to runtime/native/java_lang_reflect_Executable.h
index 222e5a0..0cfed62 100644
--- a/runtime/native/java_lang_reflect_AbstractMethod.h
+++ b/runtime/native/java_lang_reflect_Executable.h
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_
-#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_
+#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_EXECUTABLE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_EXECUTABLE_H_
 
 #include <jni.h>
 
 namespace art {
 
-void register_java_lang_reflect_AbstractMethod(JNIEnv* env);
+void register_java_lang_reflect_Executable(JNIEnv* env);
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_EXECUTABLE_H_
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 67e3fe8..c69e98c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -24,8 +24,8 @@
 #include "dex_file-inl.h"
 #include "indirect_reference_table-inl.h"
 #include "jni_internal.h"
-#include "mirror/abstract_method.h"
 #include "mirror/class-inl.h"
+#include "mirror/executable.h"
 #include "mirror/object_array-inl.h"
 #include "nth_caller_visitor.h"
 #include "scoped_thread_state_change.h"
@@ -578,9 +578,9 @@
     return nullptr;
   }
 
-  auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(javaMethod);
-  const bool accessible = abstract_method->IsAccessible();
-  ArtMethod* m = abstract_method->GetArtMethod();
+  auto* executable = soa.Decode<mirror::Executable*>(javaMethod);
+  const bool accessible = executable->IsAccessible();
+  ArtMethod* m = executable->GetArtMethod();
 
   mirror::Class* declaring_class = m->GetDeclaringClass();
   if (UNLIKELY(!declaring_class->IsInitialized())) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f144b98..15e3b1c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -108,9 +108,9 @@
 #include "native/java_lang_VMClassLoader.h"
 #include "native/java_lang_ref_FinalizerReference.h"
 #include "native/java_lang_ref_Reference.h"
-#include "native/java_lang_reflect_AbstractMethod.h"
 #include "native/java_lang_reflect_Array.h"
 #include "native/java_lang_reflect_Constructor.h"
+#include "native/java_lang_reflect_Executable.h"
 #include "native/java_lang_reflect_Field.h"
 #include "native/java_lang_reflect_Method.h"
 #include "native/java_lang_reflect_Parameter.h"
@@ -1378,9 +1378,9 @@
   register_java_lang_DexCache(env);
   register_java_lang_Object(env);
   register_java_lang_ref_FinalizerReference(env);
-  register_java_lang_reflect_AbstractMethod(env);
   register_java_lang_reflect_Array(env);
   register_java_lang_reflect_Constructor(env);
+  register_java_lang_reflect_Executable(env);
   register_java_lang_reflect_Field(env);
   register_java_lang_reflect_Method(env);
   register_java_lang_reflect_Parameter(env);
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index a71578b..9fbf875 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -34,7 +34,9 @@
   return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
 }
 
-VdexFile::Header::Header() {
+VdexFile::Header::Header(uint32_t dex_size, uint32_t verifier_deps_size)
+    : dex_size_(dex_size),
+      verifier_deps_size_(verifier_deps_size) {
   memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
   memcpy(version_, kVdexVersion, sizeof(kVdexVersion));
   DCHECK(IsMagicValid());
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 9215e52..6bea153 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -42,17 +42,22 @@
  public:
   struct Header {
    public:
-    Header();
+    Header(uint32_t dex_size, uint32_t verifier_deps_size);
 
     bool IsMagicValid() const;
     bool IsVersionValid() const;
 
+    uint32_t GetDexSize() const { return dex_size_; }
+    uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
+
    private:
     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
     static constexpr uint8_t kVdexVersion[] = { '0', '0', '0', '\0' };
 
     uint8_t magic_[4];
     uint8_t version_[4];
+    uint32_t dex_size_;
+    uint32_t verifier_deps_size_;
   };
 
   static VdexFile* Open(const std::string& vdex_filename,
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f1d3189..abd741c 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3284,7 +3284,7 @@
       }
       break;
     // Note: the following instructions encode offsets derived from class linking.
-    // As such they use Class*/Field*/AbstractMethod* as these offsets only have
+    // As such they use Class*/Field*/Executable* as these offsets only have
     // meaning if the class linking and resolution were successful.
     case Instruction::IGET_QUICK:
       VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5f5fbc8..16c7f77 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -48,8 +48,8 @@
 jclass WellKnownClasses::java_lang_NoClassDefFoundError;
 jclass WellKnownClasses::java_lang_Object;
 jclass WellKnownClasses::java_lang_OutOfMemoryError;
-jclass WellKnownClasses::java_lang_reflect_AbstractMethod;
 jclass WellKnownClasses::java_lang_reflect_Constructor;
+jclass WellKnownClasses::java_lang_reflect_Executable;
 jclass WellKnownClasses::java_lang_reflect_Field;
 jclass WellKnownClasses::java_lang_reflect_Method;
 jclass WellKnownClasses::java_lang_reflect_Proxy;
@@ -154,7 +154,7 @@
 jfieldID WellKnownClasses::java_lang_Throwable_stackTrace;
 jfieldID WellKnownClasses::java_lang_Throwable_stackState;
 jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions;
-jfieldID WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod;
+jfieldID WellKnownClasses::java_lang_reflect_Executable_artMethod;
 jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress;
@@ -237,8 +237,8 @@
   java_lang_ExceptionInInitializerError = CacheClass(env, "java/lang/ExceptionInInitializerError");
   java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError");
   java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError");
-  java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod");
   java_lang_reflect_Constructor = CacheClass(env, "java/lang/reflect/Constructor");
+  java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
   java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field");
   java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method");
   java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy");
@@ -362,7 +362,7 @@
   java_lang_Throwable_stackTrace = CacheField(env, java_lang_Throwable, false, "stackTrace", "[Ljava/lang/StackTraceElement;");
   java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "backtrace", "Ljava/lang/Object;");
   java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;");
-  java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "J");
+  java_lang_reflect_Executable_artMethod = CacheField(env, java_lang_reflect_Executable, false, "artMethod", "J");
   java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
   java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
   java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index ce710ff..b4d179c 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -59,8 +59,8 @@
   static jclass java_lang_NoClassDefFoundError;
   static jclass java_lang_Object;
   static jclass java_lang_OutOfMemoryError;
-  static jclass java_lang_reflect_AbstractMethod;
   static jclass java_lang_reflect_Constructor;
+  static jclass java_lang_reflect_Executable;
   static jclass java_lang_reflect_Field;
   static jclass java_lang_reflect_Method;
   static jclass java_lang_reflect_Proxy;
@@ -148,7 +148,7 @@
   static jfieldID dalvik_system_DexPathList_dexElements;
   static jfieldID dalvik_system_DexPathList__Element_dexFile;
   static jfieldID dalvik_system_PathClassLoader_pathList;
-  static jfieldID java_lang_reflect_AbstractMethod_artMethod;
+  static jfieldID java_lang_reflect_Executable_artMethod;
   static jfieldID java_lang_reflect_Proxy_h;
   static jfieldID java_lang_Thread_daemon;
   static jfieldID java_lang_Thread_group;
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 346e13d..39e69a3 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -1,9 +1,9 @@
 import otherpackage.OtherPackageClass;
 
 import java.io.Serializable;
-import java.lang.reflect.AbstractMethod;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -223,7 +223,7 @@
         try {
             Class<?> c = obj.getClass();
             if (c == Method.class || c == Constructor.class) {
-              c = AbstractMethod.class;
+              c = Executable.class;
             }
             method = c.getDeclaredMethod("getSignatureAttribute");
             method.setAccessible(true);
diff --git a/test/961-default-iface-resolut-generated/build b/test/961-default-iface-resolution-gen/build
similarity index 100%
rename from test/961-default-iface-resolut-generated/build
rename to test/961-default-iface-resolution-gen/build
diff --git a/test/961-default-iface-resolut-generated/expected.txt b/test/961-default-iface-resolution-gen/expected.txt
similarity index 100%
rename from test/961-default-iface-resolut-generated/expected.txt
rename to test/961-default-iface-resolution-gen/expected.txt
diff --git a/test/961-default-iface-resolut-generated/info.txt b/test/961-default-iface-resolution-gen/info.txt
similarity index 100%
rename from test/961-default-iface-resolut-generated/info.txt
rename to test/961-default-iface-resolution-gen/info.txt
diff --git a/test/961-default-iface-resolut-generated/util-src/generate_java.py b/test/961-default-iface-resolution-gen/util-src/generate_java.py
similarity index 100%
rename from test/961-default-iface-resolut-generated/util-src/generate_java.py
rename to test/961-default-iface-resolution-gen/util-src/generate_java.py
diff --git a/test/964-default-iface-init-generated/build b/test/964-default-iface-init-gen/build
similarity index 100%
rename from test/964-default-iface-init-generated/build
rename to test/964-default-iface-init-gen/build
diff --git a/test/964-default-iface-init-generated/expected.txt b/test/964-default-iface-init-gen/expected.txt
similarity index 100%
rename from test/964-default-iface-init-generated/expected.txt
rename to test/964-default-iface-init-gen/expected.txt
diff --git a/test/964-default-iface-init-generated/info.txt b/test/964-default-iface-init-gen/info.txt
similarity index 100%
rename from test/964-default-iface-init-generated/info.txt
rename to test/964-default-iface-init-gen/info.txt
diff --git a/test/964-default-iface-init-generated/src/Displayer.java b/test/964-default-iface-init-gen/src/Displayer.java
similarity index 100%
rename from test/964-default-iface-init-generated/src/Displayer.java
rename to test/964-default-iface-init-gen/src/Displayer.java
diff --git a/test/964-default-iface-init-generated/util-src/generate_java.py b/test/964-default-iface-init-gen/util-src/generate_java.py
similarity index 100%
rename from test/964-default-iface-init-generated/util-src/generate_java.py
rename to test/964-default-iface-init-gen/util-src/generate_java.py
diff --git a/test/968-default-part-compile-generated/build b/test/968-default-partial-compile-gen/build
similarity index 100%
rename from test/968-default-part-compile-generated/build
rename to test/968-default-partial-compile-gen/build
diff --git a/test/968-default-part-compile-generated/expected.txt b/test/968-default-partial-compile-gen/expected.txt
similarity index 100%
rename from test/968-default-part-compile-generated/expected.txt
rename to test/968-default-partial-compile-gen/expected.txt
diff --git a/test/968-default-part-compile-generated/info.txt b/test/968-default-partial-compile-gen/info.txt
similarity index 100%
rename from test/968-default-part-compile-generated/info.txt
rename to test/968-default-partial-compile-gen/info.txt
diff --git a/test/968-default-part-compile-generated/util-src/generate_java.py b/test/968-default-partial-compile-gen/util-src/generate_java.py
similarity index 100%
rename from test/968-default-part-compile-generated/util-src/generate_java.py
rename to test/968-default-partial-compile-gen/util-src/generate_java.py
diff --git a/test/968-default-part-compile-generated/util-src/generate_smali.py b/test/968-default-partial-compile-gen/util-src/generate_smali.py
similarity index 100%
rename from test/968-default-part-compile-generated/util-src/generate_smali.py
rename to test/968-default-partial-compile-gen/util-src/generate_smali.py
diff --git a/test/970-iface-superresolution-generated/build b/test/970-iface-super-resolution-gen/build
similarity index 100%
rename from test/970-iface-superresolution-generated/build
rename to test/970-iface-super-resolution-gen/build
diff --git a/test/970-iface-superresolution-generated/expected.txt b/test/970-iface-super-resolution-gen/expected.txt
similarity index 100%
rename from test/970-iface-superresolution-generated/expected.txt
rename to test/970-iface-super-resolution-gen/expected.txt
diff --git a/test/970-iface-superresolution-generated/info.txt b/test/970-iface-super-resolution-gen/info.txt
similarity index 100%
rename from test/970-iface-superresolution-generated/info.txt
rename to test/970-iface-super-resolution-gen/info.txt
diff --git a/test/970-iface-superresolution-generated/util-src/generate_java.py b/test/970-iface-super-resolution-gen/util-src/generate_java.py
similarity index 100%
rename from test/970-iface-superresolution-generated/util-src/generate_java.py
rename to test/970-iface-super-resolution-gen/util-src/generate_java.py
diff --git a/test/970-iface-superresolution-generated/util-src/generate_smali.py b/test/970-iface-super-resolution-gen/util-src/generate_smali.py
similarity index 100%
rename from test/970-iface-superresolution-generated/util-src/generate_smali.py
rename to test/970-iface-super-resolution-gen/util-src/generate_smali.py
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 559e963..3bcea18 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -278,11 +278,11 @@
 # Tests that require python3.
 TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \
   960-default-smali \
-  961-default-iface-resolut-generated \
-  964-default-iface-init-generated \
-  968-default-part-compile-generated \
+  961-default-iface-resolution-gen \
+  964-default-iface-init-gen \
+  968-default-partial-compile-gen \
   969-iface-super \
-  970-iface-superresolution-generated \
+  970-iface-super-resolution-gen \
   971-iface-super
 
 # Check if we have python3 to run our tests.
@@ -362,13 +362,13 @@
 # Tests that are broken with GC stress.
 # * 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
 #   hope the second process got into the expected state. The slowness of gcstress makes this bad.
-# * 961-default-iface-resolut-generated and 964-default-iface-init-generated are very long tests
-#   that often will take more than the timeout to run when gcstress is enabled. This is because
-#   gcstress slows down allocations significantly which these tests do a lot.
+# * 961-default-iface-resolution-gen and 964-default-iface-init-genare very long tests that often
+#   will take more than the timeout to run when gcstress is enabled. This is because gcstress
+#   slows down allocations significantly which these tests do a lot.
 TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
   137-cfi \
-  961-default-iface-resolut-generated \
-  964-default-iface-init-generated
+  961-default-iface-resolution-gen \
+  964-default-iface-init-gen
 
 ifneq (,$(filter gcstress,$(GC_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/tools/bisection_search/README.md b/tools/bisection_search/README.md
index 64ccb20..d641102 100644
--- a/tools/bisection_search/README.md
+++ b/tools/bisection_search/README.md
@@ -21,12 +21,14 @@
 
         ./bisection_search.py -cp classes.dex --expected-output out_int --class Test
 
-2. Raw-cmd invocation, dalvikvm command is accepted as an argument. The command
-   has to start with an executable.
+2. Raw-cmd invocation, dalvikvm command is accepted as an argument.
 
    Extra dalvikvm arguments will be placed on second position in the command
    by default. {ARGS} tag can be used to specify a custom position.
 
+   If used in device mode, the command has to exec a dalvikvm instance. Bisection
+   will fail if pid of the process started by raw-cmd is different than pid of runtime.
+
         ./bisection_search.py --raw-cmd='run.sh -cp classes.dex Test' --expected-retcode SUCCESS
         ./bisection_search.py --raw-cmd='/bin/sh art {ARGS} -cp classes.dex Test' --expected-retcode SUCCESS
 
diff --git a/tools/bisection_search/bisection_search.py b/tools/bisection_search/bisection_search.py
index 0d36aa4..b7f1907 100755
--- a/tools/bisection_search/bisection_search.py
+++ b/tools/bisection_search/bisection_search.py
@@ -34,6 +34,7 @@
 from common import FatalError
 from common import GetEnvVariableOrError
 from common import HostTestEnv
+from common import LogSeverity
 from common import RetCode
 
 
@@ -57,6 +58,9 @@
 # position in the command.
 RAW_CMD_RUNTIME_ARGS_TAG = '{ARGS}'
 
+# Default core image path relative to ANDROID_HOST_OUT.
+DEFAULT_IMAGE_RELATIVE_PATH = '/framework/core.art'
+
 class Dex2OatWrapperTestable(object):
   """Class representing a testable compilation.
 
@@ -104,10 +108,9 @@
       print('Testing methods: {0} passes: {1}.'.format(
           compiled_methods, passes_to_run))
     cmd = self._PrepareCmd(compiled_methods=compiled_methods,
-                           passes_to_run=passes_to_run,
-                           verbose_compiler=False)
+                           passes_to_run=passes_to_run)
     (output, ret_code) = self._test_env.RunCommand(
-        cmd, {'ANDROID_LOG_TAGS': '*:e'})
+        cmd, LogSeverity.ERROR)
     res = True
     if self._expected_retcode:
       res = self._expected_retcode == ret_code
@@ -126,8 +129,8 @@
     Raises:
       FatalError: An error occurred when retrieving methods list.
     """
-    cmd = self._PrepareCmd(verbose_compiler=True)
-    (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'})
+    cmd = self._PrepareCmd()
+    (output, _) = self._test_env.RunCommand(cmd, LogSeverity.INFO)
     match_methods = re.findall(r'Building ([^\n]+)\n', output)
     if not match_methods:
       raise FatalError('Failed to retrieve methods list. '
@@ -146,9 +149,8 @@
     Raises:
       FatalError: An error occurred when retrieving passes list.
     """
-    cmd = self._PrepareCmd(compiled_methods=[compiled_method],
-                           verbose_compiler=True)
-    (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'})
+    cmd = self._PrepareCmd(compiled_methods=[compiled_method])
+    (output, _) = self._test_env.RunCommand(cmd, LogSeverity.INFO)
     match_passes = re.findall(r'Starting pass: ([^\n]+)\n', output)
     if not match_passes:
       raise FatalError('Failed to retrieve passes list. '
@@ -168,9 +170,8 @@
       self._test_env.WriteLines(self._passes_to_run_path, passes_to_run)
       cmd += ['-Xcompiler-option', '--run-passes={0}'.format(
           self._passes_to_run_path)]
-    if verbose_compiler:
-      cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
-              '-verbose:compiler', '-Xcompiler-option', '-j1']
+    cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
+            '-verbose:compiler', '-Xcompiler-option', '-j1']
     cmd += self._base_cmd[self._arguments_position:]
     return cmd
 
@@ -361,8 +362,8 @@
     if not args.device:
       base_cmd += ['-XXlib:{0}'.format(args.lib)]
       if not args.image:
-        image_path = '{0}/framework/core-optimizing-pic.art'.format(
-            GetEnvVariableOrError('ANDROID_HOST_OUT'))
+        image_path = (GetEnvVariableOrError('ANDROID_HOST_OUT') +
+                      DEFAULT_IMAGE_RELATIVE_PATH)
       else:
         image_path = args.image
       base_cmd += ['-Ximage:{0}'.format(image_path)]
diff --git a/tools/bisection_search/common.py b/tools/bisection_search/common.py
index b69b606..3d92ee5 100755
--- a/tools/bisection_search/common.py
+++ b/tools/bisection_search/common.py
@@ -21,6 +21,7 @@
 import signal
 import shlex
 import shutil
+import time
 
 from subprocess import check_call
 from subprocess import PIPE
@@ -51,6 +52,48 @@
   NOTRUN = 4
 
 
+@unique
+class LogSeverity(Enum):
+  VERBOSE = 0
+  DEBUG = 1
+  INFO = 2
+  WARNING = 3
+  ERROR = 4
+  FATAL = 5
+  SILENT = 6
+
+  @property
+  def symbol(self):
+    return self.name[0]
+
+  @classmethod
+  def FromSymbol(cls, s):
+    for log_severity in LogSeverity:
+      if log_severity.symbol == s:
+        return log_severity
+    raise ValueError("{0} is not a valid log severity symbol".format(s))
+
+  def __ge__(self, other):
+    if self.__class__ is other.__class__:
+      return self.value >= other.value
+    return NotImplemented
+
+  def __gt__(self, other):
+    if self.__class__ is other.__class__:
+      return self.value > other.value
+    return NotImplemented
+
+  def __le__(self, other):
+    if self.__class__ is other.__class__:
+      return self.value <= other.value
+    return NotImplemented
+
+  def __lt__(self, other):
+    if self.__class__ is other.__class__:
+      return self.value < other.value
+      return NotImplemented
+
+
 def GetEnvVariableOrError(variable_name):
   """Gets value of an environmental variable.
 
@@ -116,23 +159,17 @@
   return (output, stderr_output, retcode)
 
 
-def _RunCommandForOutputAndLog(cmd, env, logfile, timeout=60):
-  """Runs command and logs its output. Returns the output.
+def _LogCmdOutput(logfile, cmd, output, retcode):
+  """Logs output of a command.
 
   Args:
-    cmd: list of strings, command to run.
-    env: shell environment to run the command with.
     logfile: file handle to logfile.
-    timeout: int, timeout in seconds.
-
-  Returns:
-    tuple (string, string, RetCode) stdout output, stderr output, normalized
-      return code.
+    cmd: list of strings, command.
+    output: command output.
+    retcode: RetCode, normalized retcode.
   """
-  (output, _, retcode) = RunCommandForOutput(cmd, env, PIPE, STDOUT, timeout)
   logfile.write('Command:\n{0}\n{1}\nReturn code: {2}\n'.format(
       CommandListToCommandString(cmd), output, retcode))
-  return (output, retcode)
 
 
 def CommandListToCommandString(cmd):
@@ -187,15 +224,14 @@
     """
 
   @abc.abstractmethod
-  def RunCommand(self, cmd, env_updates=None):
-    """Runs command in environment with updated environmental variables.
+  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
+    """Runs command in environment.
 
     Args:
       cmd: list of strings, command to run.
-      env_updates: dict, string to string, maps names of variables to their
-        updated values.
+      log_severity: LogSeverity, minimum severity of logs included in output.
     Returns:
-      tuple (string, string, int) stdout output, stderr output, return code.
+      tuple (string, int) output, return code.
     """
 
   @abc.abstractproperty
@@ -262,13 +298,17 @@
       f.writelines('{0}\n'.format(line) for line in lines)
     return
 
-  def RunCommand(self, cmd, env_updates=None):
-    if not env_updates:
-      env_updates = {}
+  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
     self._EmptyDexCache()
     env = self._shell_env.copy()
-    env.update(env_updates)
-    return _RunCommandForOutputAndLog(cmd, env, self._logfile, self._timeout)
+    env.update({'ANDROID_LOG_TAGS':'*:' + log_severity.symbol.lower()})
+    (output, err_output, retcode) = RunCommandForOutput(
+        cmd, env, PIPE, PIPE, self._timeout)
+    # We append err_output to output to stay consistent with DeviceTestEnv
+    # implementation.
+    output += err_output
+    _LogCmdOutput(self._logfile, cmd, output, retcode)
+    return (output, retcode)
 
   @property
   def logfile(self):
@@ -341,26 +381,63 @@
       self._AdbPush(temp_file.name, file_path)
     return
 
-  def RunCommand(self, cmd, env_updates=None):
-    if not env_updates:
-      env_updates = {}
+  def _ExtractPid(self, brief_log_line):
+    """Extracts PID from a single logcat line in brief format."""
+    pid_start_idx = brief_log_line.find('(') + 2
+    if pid_start_idx == -1:
+      return None
+    pid_end_idx = brief_log_line.find(')', pid_start_idx)
+    if pid_end_idx == -1:
+      return None
+    return brief_log_line[pid_start_idx:pid_end_idx]
+
+  def _ExtractSeverity(self, brief_log_line):
+    """Extracts LogSeverity from a single logcat line in brief format."""
+    if not brief_log_line:
+      return None
+    return LogSeverity.FromSymbol(brief_log_line[0])
+
+  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
     self._EmptyDexCache()
-    if 'ANDROID_DATA' not in env_updates:
-      env_updates['ANDROID_DATA'] = self._device_env_path
-    env_updates_cmd = ' '.join(['{0}={1}'.format(var, val) for var, val
-                                in env_updates.items()])
-    cmd = CommandListToCommandString(cmd)
-    adb = 'adb'
+    env_vars_cmd = 'ANDROID_DATA={0} ANDROID_LOG_TAGS=*:i'.format(
+        self._device_env_path)
+    adb_cmd = ['adb']
     if self._specific_device:
-      adb += ' -s ' + self._specific_device
-    cmd = '{0} shell "logcat -c && {1} {2}"'.format(
-        adb, env_updates_cmd, cmd)
-    (output, retcode) = _RunCommandForOutputAndLog(
-        shlex.split(cmd), self._shell_env, self._logfile, self._timeout)
-    logcat_cmd = 'adb shell "logcat -d -s -b main dex2oat:* dex2oatd:*"'
-    (err_output, _) = _RunCommandForOutputAndLog(
-        shlex.split(logcat_cmd), self._shell_env, self._logfile)
-    return (output + err_output, retcode)
+      adb_cmd += ['-s', self._specific_device]
+    logcat_cmd = adb_cmd + ['logcat', '-v', 'brief', '-s', '-b', 'main',
+                            '-T', '1', 'dex2oat:*', 'dex2oatd:*']
+    logcat_proc = Popen(logcat_cmd, stdout=PIPE, stderr=STDOUT,
+                        universal_newlines=True)
+    cmd_str = CommandListToCommandString(cmd)
+    # Print PID of the shell and exec command. We later retrieve this PID and
+    # use it to filter dex2oat logs, keeping those with matching parent PID.
+    device_cmd = ('echo $$ && ' + env_vars_cmd + ' exec ' + cmd_str)
+    cmd = adb_cmd + ['shell', device_cmd]
+    (output, _, retcode) = RunCommandForOutput(cmd, self._shell_env, PIPE,
+                                               STDOUT, self._timeout)
+    # We need to make sure to only kill logcat once all relevant logs arrive.
+    # Sleep is used for simplicity.
+    time.sleep(0.5)
+    logcat_proc.kill()
+    end_of_first_line = output.find('\n')
+    if end_of_first_line != -1:
+      parent_pid = output[:end_of_first_line]
+      output = output[end_of_first_line + 1:]
+      logcat_output, _ = logcat_proc.communicate()
+      logcat_lines = logcat_output.splitlines(keepends=True)
+      dex2oat_pids = []
+      for line in logcat_lines:
+        # Dex2oat was started by our runtime instance.
+        if 'Running dex2oat (parent PID = ' + parent_pid in line:
+          dex2oat_pids.append(self._ExtractPid(line))
+          break
+      if dex2oat_pids:
+        for line in logcat_lines:
+          if (self._ExtractPid(line) in dex2oat_pids and
+              self._ExtractSeverity(line) >= log_severity):
+            output += line
+    _LogCmdOutput(self._logfile, cmd, output, retcode)
+    return (output, retcode)
 
   @property
   def logfile(self):
diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt
index 95f0c2d..0e289a6 100644
--- a/tools/libcore_failures_concurrent_collector.txt
+++ b/tools/libcore_failures_concurrent_collector.txt
@@ -10,11 +10,4 @@
  */
 
 [
-{
-  description: "Assertion failing on the concurrent collector configuration.",
-  result: EXEC_FAILED,
-  names: ["jsr166.LinkedTransferQueueTest#testTransfer2",
-          "jsr166.LinkedTransferQueueTest#testWaitingConsumer"],
-  bug: 25883050
-}
 ]