Merge "Stress profile saving for gc-stress tests"
diff --git a/Android.bp b/Android.bp
index ad42d3f..bb92e5f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,7 +1,6 @@
 // TODO: These should be handled with transitive static library dependencies
 art_static_dependencies = [
     // Note: the order is important because of static linking resolution.
-    "libdexfile",
     "libziparchive",
     "libnativehelper",
     "libnativebridge",
diff --git a/Android.mk b/Android.mk
index 361ceec..2489308 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,7 @@
 include $(art_path)/oatdump/Android.mk
 include $(art_path)/tools/Android.mk
 include $(art_path)/tools/ahat/Android.mk
+include $(art_path)/tools/amm/Android.mk
 include $(art_path)/tools/dexfuzz/Android.mk
 include $(art_path)/libart_fake/Android.mk
 
@@ -486,8 +487,10 @@
                         $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
                         $(TARGET_CORE_IMG_OUT_BASE).art \
                         $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+	# remove libartd.so and libdexfiled.so from public.libraries.txt because golem builds
+	# won't have it.
 	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
-	# remove libartd.so from public.libraries.txt because golem builds won't have it.
+	sed -i '/libdexfiled.so/d' $(TARGET_OUT)/etc/public.libraries.txt
 
 ########################################################################
 # Phony target for building what go/lem requires on host.
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 4539659..ba08d79 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -184,7 +184,6 @@
     },
     generated_sources: ["art_compiler_operator_srcs"],
     shared_libs: [
-        "libdexfile",
         "libbase",
         "libcutils",  // for atrace.
         "liblzma",
@@ -250,6 +249,7 @@
     },
     shared_libs: [
         "libart",
+        "libdexfile",
     ],
 
     pgo: {
@@ -295,6 +295,7 @@
     },
     shared_libs: [
         "libartd",
+        "libdexfiled",
     ],
 }
 
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 3c5a37f..60de722 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -618,14 +618,18 @@
 
  protected:
   // Patch info used for recording locations of required linker patches and their targets,
-  // i.e. target method, string, type or code identified by their dex file and index.
+  // i.e. target method, string, type or code identified by their dex file and index,
+  // or .data.bimg.rel.ro entries identified by the boot image offset.
   template <typename LabelType>
   struct PatchInfo {
-    PatchInfo(const DexFile& target_dex_file, uint32_t target_index)
-        : dex_file(target_dex_file), index(target_index) { }
+    PatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
+        : target_dex_file(dex_file), offset_or_index(off_or_idx), label() { }
 
-    const DexFile& dex_file;
-    uint32_t index;
+    // Target dex file or null for .data.bmig.rel.ro patches.
+    const DexFile* target_dex_file;
+    // Either the boot image offset (to write to .data.bmig.rel.ro) or string/type/method index.
+    uint32_t offset_or_index;
+    // Label for the instruction to patch.
     LabelType label;
   };
 
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3fd88e3..60f8f98 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1395,11 +1395,11 @@
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       baker_read_barrier_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_string_patches_(StringReferenceValueComparator(),
@@ -4447,11 +4447,11 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
       // Add ADRP with its PC-relative method patch.
-      vixl::aarch64::Label* adrp_label = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+      vixl::aarch64::Label* adrp_label = NewBootImageMethodPatch(invoke->GetTargetMethod());
       EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
       // Add ADD with its PC-relative method patch.
       vixl::aarch64::Label* add_label =
-          NewPcRelativeMethodPatch(invoke->GetTargetMethod(), adrp_label);
+          NewBootImageMethodPatch(invoke->GetTargetMethod(), adrp_label);
       EmitAddPlaceholder(add_label, XRegisterFrom(temp), XRegisterFrom(temp));
       break;
     }
@@ -4559,51 +4559,47 @@
   codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ __LINE__);
 }
 
-vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeMethodPatch(
+vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageMethodPatch(
     MethodReference target_method,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            adrp_label,
-                            &pc_relative_method_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, adrp_label, &boot_image_method_patches_);
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewMethodBssEntryPatch(
     MethodReference target_method,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            adrp_label,
-                            &method_bss_entry_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, adrp_label, &method_bss_entry_patches_);
 }
 
-vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(
+vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageTypePatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(dex_file, type_index.index_, adrp_label, &pc_relative_type_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, adrp_label, &boot_image_type_patches_);
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewBssEntryTypePatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(dex_file, type_index.index_, adrp_label, &type_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, adrp_label, &type_bss_entry_patches_);
 }
 
-vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeStringPatch(
+vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageStringPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     vixl::aarch64::Label* adrp_label) {
-  return
-      NewPcRelativePatch(dex_file, string_index.index_, adrp_label, &pc_relative_string_patches_);
+  return NewPcRelativePatch(
+      &dex_file, string_index.index_, adrp_label, &boot_image_string_patches_);
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewStringBssEntryPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(dex_file, string_index.index_, adrp_label, &string_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, string_index.index_, adrp_label, &string_bss_entry_patches_);
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewBakerReadBarrierPatch(uint32_t custom_data) {
@@ -4612,7 +4608,7 @@
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativePatch(
-    const DexFile& dex_file,
+    const DexFile* dex_file,
     uint32_t offset_or_index,
     vixl::aarch64::Label* adrp_label,
     ArenaDeque<PcRelativePatchInfo>* patches) {
@@ -4679,7 +4675,7 @@
     ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
     linker_patches->push_back(Factory(info.label.GetLocation(),
-                                      &info.target_dex_file,
+                                      info.target_dex_file,
                                       info.pc_insn_label->GetLocation(),
                                       info.offset_or_index));
   }
@@ -4688,27 +4684,27 @@
 void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_method_patches_.size() +
+      boot_image_method_patches_.size() +
       method_bss_entry_patches_.size() +
-      pc_relative_type_patches_.size() +
+      boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
-      pc_relative_string_patches_.size() +
+      boot_image_string_patches_.size() +
       string_bss_entry_patches_.size() +
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
-        pc_relative_method_patches_, linker_patches);
+        boot_image_method_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
-    DCHECK(pc_relative_method_patches_.empty());
+    DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
@@ -4876,11 +4872,11 @@
       // Add ADRP with its PC-relative type patch.
       const DexFile& dex_file = cls->GetDexFile();
       dex::TypeIndex type_index = cls->GetTypeIndex();
-      vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
+      vixl::aarch64::Label* adrp_label = codegen_->NewBootImageTypePatch(dex_file, type_index);
       codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
       // Add ADD with its PC-relative type patch.
       vixl::aarch64::Label* add_label =
-          codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label);
+          codegen_->NewBootImageTypePatch(dex_file, type_index, adrp_label);
       codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
       break;
     }
@@ -4897,11 +4893,11 @@
       // Add ADRP with its PC-relative type patch.
       const DexFile& dex_file = cls->GetDexFile();
       dex::TypeIndex type_index = cls->GetTypeIndex();
-      vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
+      vixl::aarch64::Label* adrp_label = codegen_->NewBootImageTypePatch(dex_file, type_index);
       codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
       // Add LDR with its PC-relative type patch.
       vixl::aarch64::Label* ldr_label =
-          codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label);
+          codegen_->NewBootImageTypePatch(dex_file, type_index, adrp_label);
       codegen_->EmitLdrOffsetPlaceholder(ldr_label, out.W(), out.X());
       // Extract the reference from the slot data, i.e. clear the hash bits.
       int32_t masked_hash = ClassTable::TableSlot::MaskHash(
@@ -5044,11 +5040,11 @@
       // Add ADRP with its PC-relative String patch.
       const DexFile& dex_file = load->GetDexFile();
       const dex::StringIndex string_index = load->GetStringIndex();
-      vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index);
+      vixl::aarch64::Label* adrp_label = codegen_->NewBootImageStringPatch(dex_file, string_index);
       codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
       // Add ADD with its PC-relative String patch.
       vixl::aarch64::Label* add_label =
-          codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
+          codegen_->NewBootImageStringPatch(dex_file, string_index, adrp_label);
       codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
       return;
     }
@@ -5064,11 +5060,11 @@
       // Add ADRP with its PC-relative String patch.
       const DexFile& dex_file = load->GetDexFile();
       const dex::StringIndex string_index = load->GetStringIndex();
-      vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index);
+      vixl::aarch64::Label* adrp_label = codegen_->NewBootImageStringPatch(dex_file, string_index);
       codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
       // Add LDR with its PC-relative String patch.
       vixl::aarch64::Label* ldr_label =
-          codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
+          codegen_->NewBootImageStringPatch(dex_file, string_index, adrp_label);
       codegen_->EmitLdrOffsetPlaceholder(ldr_label, out.W(), out.X());
       return;
     }
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index f92c94f..e34f799 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -565,8 +565,8 @@
   // to be bound before the instruction. The instruction will be either the
   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
   // to the associated ADRP patch label).
-  vixl::aarch64::Label* NewPcRelativeMethodPatch(MethodReference target_method,
-                                                 vixl::aarch64::Label* adrp_label = nullptr);
+  vixl::aarch64::Label* NewBootImageMethodPatch(MethodReference target_method,
+                                                vixl::aarch64::Label* adrp_label = nullptr);
 
   // Add a new .bss entry method patch for an instruction and return
   // the label to be bound before the instruction. The instruction will be
@@ -579,9 +579,9 @@
   // to be bound before the instruction. The instruction will be either the
   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
   // to the associated ADRP patch label).
-  vixl::aarch64::Label* NewPcRelativeTypePatch(const DexFile& dex_file,
-                                               dex::TypeIndex type_index,
-                                               vixl::aarch64::Label* adrp_label = nullptr);
+  vixl::aarch64::Label* NewBootImageTypePatch(const DexFile& dex_file,
+                                              dex::TypeIndex type_index,
+                                              vixl::aarch64::Label* adrp_label = nullptr);
 
   // Add a new .bss entry type patch for an instruction and return the label
   // to be bound before the instruction. The instruction will be either the
@@ -595,9 +595,9 @@
   // to be bound before the instruction. The instruction will be either the
   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
   // to the associated ADRP patch label).
-  vixl::aarch64::Label* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                 dex::StringIndex string_index,
-                                                 vixl::aarch64::Label* adrp_label = nullptr);
+  vixl::aarch64::Label* NewBootImageStringPatch(const DexFile& dex_file,
+                                                dex::StringIndex string_index,
+                                                vixl::aarch64::Label* adrp_label = nullptr);
 
   // Add a new .bss entry string patch for an instruction and return the label
   // to be bound before the instruction. The instruction will be either the
@@ -777,17 +777,12 @@
   vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value);
   vixl::aarch64::Literal<uint64_t>* DeduplicateUint64Literal(uint64_t value);
 
-  // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
-  // and boot image strings/types. The only difference is the interpretation of the
-  // offset_or_index.
-  struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
-        : target_dex_file(dex_file), offset_or_index(off_or_idx), label(), pc_insn_label() { }
+  // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
+  // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
+  struct PcRelativePatchInfo : PatchInfo<vixl::aarch64::Label> {
+    PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
+        : PatchInfo<vixl::aarch64::Label>(dex_file, off_or_idx), pc_insn_label() { }
 
-    const DexFile& target_dex_file;
-    // Either the dex cache array element offset or the string/type index.
-    uint32_t offset_or_index;
-    vixl::aarch64::Label label;
     vixl::aarch64::Label* pc_insn_label;
   };
 
@@ -798,7 +793,7 @@
     uint32_t custom_data;
   };
 
-  vixl::aarch64::Label* NewPcRelativePatch(const DexFile& dex_file,
+  vixl::aarch64::Label* NewPcRelativePatch(const DexFile* dex_file,
                                            uint32_t offset_or_index,
                                            vixl::aarch64::Label* adrp_label,
                                            ArenaDeque<PcRelativePatchInfo>* patches);
@@ -826,15 +821,15 @@
   // Deduplication map for 64-bit literals, used for non-patchable method address or method code.
   Uint64ToLiteralMap uint64_literals_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
   // PC-relative method patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
   // PC-relative type patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
   // PC-relative String patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
   // Baker read barrier patch info.
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 6d49b32..2f495fc 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -2354,11 +2354,11 @@
       isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       baker_read_barrier_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_string_patches_(StringReferenceValueComparator(),
@@ -7131,7 +7131,7 @@
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       codegen_->EmitMovwMovtPlaceholder(labels, out);
       break;
     }
@@ -7146,7 +7146,7 @@
     case HLoadClass::LoadKind::kBootImageClassTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       codegen_->EmitMovwMovtPlaceholder(labels, out);
       __ Ldr(out, MemOperand(out, /* offset */ 0));
       // Extract the reference from the slot data, i.e. clear the hash bits.
@@ -7293,7 +7293,7 @@
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       codegen_->EmitMovwMovtPlaceholder(labels, out);
       return;
     }
@@ -7307,7 +7307,7 @@
     case HLoadString::LoadKind::kBootImageInternTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       codegen_->EmitMovwMovtPlaceholder(labels, out);
       __ Ldr(out, MemOperand(out, /* offset */ 0));
       return;
@@ -8893,7 +8893,7 @@
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
-      PcRelativePatchInfo* labels = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+      PcRelativePatchInfo* labels = NewBootImageMethodPatch(invoke->GetTargetMethod());
       vixl32::Register temp_reg = RegisterFrom(temp);
       EmitMovwMovtPlaceholder(labels, temp_reg);
       break;
@@ -8998,42 +8998,40 @@
   }
 }
 
-CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeMethodPatch(
+CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewBootImageMethodPatch(
     MethodReference target_method) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            &pc_relative_method_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, &boot_image_method_patches_);
 }
 
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewMethodBssEntryPatch(
     MethodReference target_method) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            &method_bss_entry_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, &method_bss_entry_patches_);
 }
 
-CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeTypePatch(
+CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewBootImageTypePatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, &boot_image_type_patches_);
 }
 
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewTypeBssEntryPatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, &type_bss_entry_patches_);
 }
 
-CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeStringPatch(
+CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewBootImageStringPatch(
     const DexFile& dex_file, dex::StringIndex string_index) {
-  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
+  return NewPcRelativePatch(&dex_file, string_index.index_, &boot_image_string_patches_);
 }
 
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewStringBssEntryPatch(
     const DexFile& dex_file, dex::StringIndex string_index) {
-  return NewPcRelativePatch(dex_file, string_index.index_, &string_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, string_index.index_, &string_bss_entry_patches_);
 }
 
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativePatch(
-    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
+    const DexFile* dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   patches->emplace_back(dex_file, offset_or_index);
   return &patches->back();
 }
@@ -9075,45 +9073,45 @@
     const ArenaDeque<PcRelativePatchInfo>& infos,
     ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
-    const DexFile& dex_file = info.target_dex_file;
+    const DexFile* dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
     DCHECK(info.add_pc_label.IsBound());
     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.GetLocation());
     // Add MOVW patch.
     DCHECK(info.movw_label.IsBound());
     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.GetLocation());
-    linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
+    linker_patches->push_back(Factory(movw_offset, dex_file, add_pc_offset, offset_or_index));
     // Add MOVT patch.
     DCHECK(info.movt_label.IsBound());
     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.GetLocation());
-    linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
+    linker_patches->push_back(Factory(movt_offset, dex_file, add_pc_offset, offset_or_index));
   }
 }
 
 void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() +
+      /* MOVW+MOVT for each entry */ 2u * boot_image_method_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() +
-      /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
+      /* MOVW+MOVT for each entry */ 2u * boot_image_type_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
-      /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
+      /* MOVW+MOVT for each entry */ 2u * boot_image_string_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * string_bss_entry_patches_.size() +
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
-        pc_relative_method_patches_, linker_patches);
+        boot_image_method_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
-    DCHECK(pc_relative_method_patches_.empty());
+    DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 38570bb..bbc715c 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -552,32 +552,34 @@
 
   void MoveFromReturnRegister(Location trg, DataType::Type type) OVERRIDE;
 
-  // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
-  // and boot image strings/types. The only difference is the interpretation of the
-  // offset_or_index. The PC-relative address is loaded with three instructions,
+  // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
+  // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
+  //
+  // The PC-relative address is loaded with three instructions,
   // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset
   // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we
   // currently emit these 3 instructions together, instruction scheduling could
   // split this sequence apart, so we keep separate labels for each of them.
   struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
+    PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
         : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
     PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
 
-    const DexFile& target_dex_file;
-    // Either the dex cache array element offset or the string/type index.
+    // Target dex file or null for .data.bmig.rel.ro patches.
+    const DexFile* target_dex_file;
+    // Either the boot image offset (to write to .data.bmig.rel.ro) or string/type/method index.
     uint32_t offset_or_index;
     vixl::aarch32::Label movw_label;
     vixl::aarch32::Label movt_label;
     vixl::aarch32::Label add_pc_label;
   };
 
-  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
+  PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method);
   PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
+  PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
-  PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                dex::StringIndex string_index);
+  PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
+                                               dex::StringIndex string_index);
   PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
                                               dex::StringIndex string_index);
 
@@ -774,7 +776,7 @@
   };
 
   VIXLUInt32Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
-  PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
+  PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
                                           uint32_t offset_or_index,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
@@ -797,15 +799,15 @@
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
   // PC-relative method patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
   // PC-relative type patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
   // PC-relative String patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
   // Baker read barrier patch info.
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 97604b3..d01b895 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1017,11 +1017,11 @@
       isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -1583,7 +1583,7 @@
     const ArenaDeque<PcRelativePatchInfo>& infos,
     ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
-    const DexFile& dex_file = info.target_dex_file;
+    const DexFile* dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
     DCHECK(info.label.IsBound());
     uint32_t literal_offset = __ GetLabelLocation(&info.label);
@@ -1593,33 +1593,33 @@
     uint32_t pc_rel_offset = info_high.pc_rel_label.IsBound()
         ? __ GetLabelLocation(&info_high.pc_rel_label)
         : __ GetPcRelBaseLabelLocation();
-    linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
+    linker_patches->push_back(Factory(literal_offset, dex_file, pc_rel_offset, offset_or_index));
   }
 }
 
 void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_method_patches_.size() +
+      boot_image_method_patches_.size() +
       method_bss_entry_patches_.size() +
-      pc_relative_type_patches_.size() +
+      boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
-      pc_relative_string_patches_.size() +
+      boot_image_string_patches_.size() +
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
-        pc_relative_method_patches_, linker_patches);
+        boot_image_method_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
-    DCHECK(pc_relative_method_patches_.empty());
+    DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
@@ -1630,54 +1630,51 @@
   DCHECK_EQ(size, linker_patches->size());
 }
 
-CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeMethodPatch(
+CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageMethodPatch(
     MethodReference target_method,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            info_high,
-                            &pc_relative_method_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, info_high, &boot_image_method_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
     MethodReference target_method,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            info_high,
-                            &method_bss_entry_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, info_high, &method_bss_entry_patches_);
 }
 
-CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
+CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageTypePatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &boot_image_type_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
 }
 
-CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
+CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageStringPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
+  return NewPcRelativePatch(
+      &dex_file, string_index.index_, info_high, &boot_image_string_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewStringBssEntryPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
-    const DexFile& dex_file,
+    const DexFile* dex_file,
     uint32_t offset_or_index,
     const PcRelativePatchInfo* info_high,
     ArenaDeque<PcRelativePatchInfo>* patches) {
@@ -7828,9 +7825,9 @@
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
-      PcRelativePatchInfo* info_high = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+      PcRelativePatchInfo* info_high = NewBootImageMethodPatch(invoke->GetTargetMethod());
       PcRelativePatchInfo* info_low =
-          NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
+          NewBootImageMethodPatch(invoke->GetTargetMethod(), info_high);
       Register temp_reg = temp.AsRegister<Register>();
       EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
       __ Addiu(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
@@ -8046,9 +8043,9 @@
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
                                                      out,
                                                      base_or_current_method_reg);
@@ -8072,9 +8069,9 @@
     case HLoadClass::LoadKind::kBootImageClassTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
                                                      out,
                                                      base_or_current_method_reg);
@@ -8241,9 +8238,9 @@
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
                                                      out,
                                                      base_or_current_method_reg);
@@ -8266,9 +8263,9 @@
     case HLoadString::LoadKind::kBootImageInternTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
                                                      out,
                                                      base_or_current_method_reg);
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 32b3e42..d87cfc0 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -576,8 +576,9 @@
   void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
   void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
-  // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
-  // and boot image strings. The only difference is the interpretation of the offset_or_index.
+  // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
+  // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
+  //
   // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
   // two patches/infos. There can be more than two patches/infos if the instruction supplying
   // the high half is shared with e.g. a slow path, while the low half is supplied by separate
@@ -592,21 +593,14 @@
   //     ...
   //     sw    r2, low(r1)    // patch
   //     b     back
-  struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file,
+  struct PcRelativePatchInfo : PatchInfo<MipsLabel> {
+    PcRelativePatchInfo(const DexFile* dex_file,
                         uint32_t off_or_idx,
                         const PcRelativePatchInfo* info_high)
-        : target_dex_file(dex_file),
-          offset_or_index(off_or_idx),
-          label(),
+        : PatchInfo<MipsLabel>(dex_file, off_or_idx),
           pc_rel_label(),
           patch_info_high(info_high) { }
 
-    const DexFile& target_dex_file;
-    // Either the dex cache array element offset or the string/type index.
-    uint32_t offset_or_index;
-    // Label for the instruction to patch.
-    MipsLabel label;
     // Label for the instruction corresponding to PC+0. Not bound or used in low half patches.
     // Not bound in high half patches on R2 when using HMipsComputeBaseMethodAddress.
     // Bound in high half patches on R2 when using the NAL instruction instead of
@@ -621,19 +615,19 @@
     DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
   };
 
-  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
-                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
+                                               const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
                                               const PcRelativePatchInfo* info_high = nullptr);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
-                                              dex::TypeIndex type_index,
-                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file,
+                                             dex::TypeIndex type_index,
+                                             const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
                                             dex::TypeIndex type_index,
                                             const PcRelativePatchInfo* info_high = nullptr);
-  PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                dex::StringIndex string_index,
-                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
+                                               dex::StringIndex string_index,
+                                               const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
                                               dex::StringIndex string_index,
                                               const PcRelativePatchInfo* info_high = nullptr);
@@ -675,7 +669,7 @@
   using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
 
   Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
-  PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
+  PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
                                           uint32_t offset_or_index,
                                           const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
@@ -696,15 +690,15 @@
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
   // PC-relative method patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
   // PC-relative type patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
   // PC-relative String patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
 
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index f1bb5c1..e3529f1 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -962,11 +962,11 @@
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
                        graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_string_patches_(StringReferenceValueComparator(),
                           graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -1499,39 +1499,39 @@
     const ArenaDeque<PcRelativePatchInfo>& infos,
     ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const PcRelativePatchInfo& info : infos) {
-    const DexFile& dex_file = info.target_dex_file;
+    const DexFile* dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
     DCHECK(info.label.IsBound());
     uint32_t literal_offset = __ GetLabelLocation(&info.label);
     const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
     uint32_t pc_rel_offset = __ GetLabelLocation(&info_high.label);
-    linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
+    linker_patches->push_back(Factory(literal_offset, dex_file, pc_rel_offset, offset_or_index));
   }
 }
 
 void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_method_patches_.size() +
+      boot_image_method_patches_.size() +
       method_bss_entry_patches_.size() +
-      pc_relative_type_patches_.size() +
+      boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
-      pc_relative_string_patches_.size() +
+      boot_image_string_patches_.size() +
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
-        pc_relative_method_patches_, linker_patches);
+        boot_image_method_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
-    DCHECK(pc_relative_method_patches_.empty());
+    DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
-        pc_relative_type_patches_, linker_patches);
+        boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        pc_relative_string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
@@ -1542,54 +1542,51 @@
   DCHECK_EQ(size, linker_patches->size());
 }
 
-CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeMethodPatch(
+CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewBootImageMethodPatch(
     MethodReference target_method,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            info_high,
-                            &pc_relative_method_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, info_high, &boot_image_method_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewMethodBssEntryPatch(
     MethodReference target_method,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(*target_method.dex_file,
-                            target_method.index,
-                            info_high,
-                            &method_bss_entry_patches_);
+  return NewPcRelativePatch(
+      target_method.dex_file, target_method.index, info_high, &method_bss_entry_patches_);
 }
 
-CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeTypePatch(
+CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewBootImageTypePatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &boot_image_type_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewTypeBssEntryPatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
 }
 
-CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeStringPatch(
+CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewBootImageStringPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
+  return NewPcRelativePatch(
+      &dex_file, string_index.index_, info_high, &boot_image_string_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewStringBssEntryPatch(
     const DexFile& dex_file,
     dex::StringIndex string_index,
     const PcRelativePatchInfo* info_high) {
-  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
+  return NewPcRelativePatch(&dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch(
-    const DexFile& dex_file,
+    const DexFile* dex_file,
     uint32_t offset_or_index,
     const PcRelativePatchInfo* info_high,
     ArenaDeque<PcRelativePatchInfo>* patches) {
@@ -5917,9 +5914,9 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
-          NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+          NewBootImageMethodPatch(invoke->GetTargetMethod());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
-          NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
+          NewBootImageMethodPatch(invoke->GetTargetMethod(), info_high);
       EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
       break;
@@ -6099,9 +6096,9 @@
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(out, AT, /* placeholder */ 0x5678);
       break;
@@ -6119,9 +6116,9 @@
     case HLoadClass::LoadKind::kBootImageClassTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+          codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Lwu(out, AT, /* placeholder */ 0x5678);
       // Extract the reference from the slot data, i.e. clear the hash bits.
@@ -6235,9 +6232,9 @@
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(out, AT, /* placeholder */ 0x5678);
       return;
@@ -6254,9 +6251,9 @@
     case HLoadString::LoadKind::kBootImageInternTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
       CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
-          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+          codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Lwu(out, AT, /* placeholder */ 0x5678);
       return;
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index d479410..ddeb3eb 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -555,9 +555,9 @@
   void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
   void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
-  // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays,
-  // boot image strings and method calls. The only difference is the interpretation of
-  // the offset_or_index.
+  // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
+  // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
+  //
   // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
   // two patches/infos. There can be more than two patches/infos if the instruction supplying
   // the high half is shared with e.g. a slow path, while the low half is supplied by separate
@@ -571,20 +571,13 @@
   //     ...
   //     sw    r2, low(r1)    // patch
   //     bc    back
-  struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file,
+  struct PcRelativePatchInfo : PatchInfo<Mips64Label> {
+    PcRelativePatchInfo(const DexFile* dex_file,
                         uint32_t off_or_idx,
                         const PcRelativePatchInfo* info_high)
-        : target_dex_file(dex_file),
-          offset_or_index(off_or_idx),
-          label(),
+        : PatchInfo<Mips64Label>(dex_file, off_or_idx),
           patch_info_high(info_high) { }
 
-    const DexFile& target_dex_file;
-    // Either the dex cache array element offset or the string/type/method index.
-    uint32_t offset_or_index;
-    // Label for the instruction to patch.
-    Mips64Label label;
     // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
     const PcRelativePatchInfo* patch_info_high;
 
@@ -593,19 +586,19 @@
     DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
   };
 
-  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
-                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
+                                               const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
                                               const PcRelativePatchInfo* info_high = nullptr);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
-                                              dex::TypeIndex type_index,
-                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file,
+                                             dex::TypeIndex type_index,
+                                             const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
                                             dex::TypeIndex type_index,
                                             const PcRelativePatchInfo* info_high = nullptr);
-  PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                dex::StringIndex string_index,
-                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
+                                               dex::StringIndex string_index,
+                                               const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
                                               dex::StringIndex string_index,
                                               const PcRelativePatchInfo* info_high = nullptr);
@@ -639,7 +632,7 @@
   Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
   Literal* DeduplicateUint64Literal(uint64_t value);
 
-  PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
+  PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
                                           uint32_t offset_or_index,
                                           const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
@@ -663,15 +656,15 @@
   // address.
   Uint64ToLiteralMap uint64_literals_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
   // PC-relative method patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
   // PC-relative type patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
+  ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
   // PC-relative type patch info for kBssEntry.
   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
 
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 5fede80..6bf0458 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1028,7 +1028,7 @@
       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-      string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+      boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
       jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -4528,7 +4528,7 @@
       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
                                                                 temp.AsRegister<Register>());
       __ leal(temp.AsRegister<Register>(), Address(base_reg, CodeGeneratorX86::kDummy32BitOffset));
-      RecordBootMethodPatch(invoke);
+      RecordBootImageMethodPatch(invoke);
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
@@ -4538,10 +4538,7 @@
       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
                                                                 temp.AsRegister<Register>());
       __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
-      // Bind a new fixup label at the end of the "movl" insn.
-      __ Bind(NewMethodBssEntryPatch(
-          invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress(),
-          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())));
+      RecordMethodBssEntryPatch(invoke);
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -4598,56 +4595,55 @@
   RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
 }
 
-void CodeGeneratorX86::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) {
+void CodeGeneratorX86::RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke) {
   DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
-  HX86ComputeBaseMethodAddress* address =
+  HX86ComputeBaseMethodAddress* method_address =
       invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
-  boot_image_method_patches_.emplace_back(address,
-                                          *invoke->GetTargetMethod().dex_file,
-                                          invoke->GetTargetMethod().index);
+  boot_image_method_patches_.emplace_back(
+      method_address, invoke->GetTargetMethod().dex_file, invoke->GetTargetMethod().index);
   __ Bind(&boot_image_method_patches_.back().label);
 }
 
-Label* CodeGeneratorX86::NewMethodBssEntryPatch(
-    HX86ComputeBaseMethodAddress* method_address,
-    MethodReference target_method) {
+void CodeGeneratorX86::RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke) {
+  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
+  HX86ComputeBaseMethodAddress* method_address =
+      invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
   // Add the patch entry and bind its label at the end of the instruction.
-  method_bss_entry_patches_.emplace_back(method_address,
-                                         *target_method.dex_file,
-                                         target_method.index);
-  return &method_bss_entry_patches_.back().label;
+  method_bss_entry_patches_.emplace_back(
+      method_address, &GetGraph()->GetDexFile(), invoke->GetDexMethodIndex());
+  __ Bind(&method_bss_entry_patches_.back().label);
 }
 
-void CodeGeneratorX86::RecordBootTypePatch(HLoadClass* load_class) {
-  HX86ComputeBaseMethodAddress* address = load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
-  boot_image_type_patches_.emplace_back(address,
-                                        load_class->GetDexFile(),
-                                        load_class->GetTypeIndex().index_);
+void CodeGeneratorX86::RecordBootImageTypePatch(HLoadClass* load_class) {
+  HX86ComputeBaseMethodAddress* method_address =
+      load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
+  boot_image_type_patches_.emplace_back(
+      method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   __ Bind(&boot_image_type_patches_.back().label);
 }
 
 Label* CodeGeneratorX86::NewTypeBssEntryPatch(HLoadClass* load_class) {
-  HX86ComputeBaseMethodAddress* address =
+  HX86ComputeBaseMethodAddress* method_address =
       load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
   type_bss_entry_patches_.emplace_back(
-      address, load_class->GetDexFile(), load_class->GetTypeIndex().index_);
+      method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   return &type_bss_entry_patches_.back().label;
 }
 
-void CodeGeneratorX86::RecordBootStringPatch(HLoadString* load_string) {
-  HX86ComputeBaseMethodAddress* address = load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
-  string_patches_.emplace_back(address,
-                               load_string->GetDexFile(),
-                               load_string->GetStringIndex().index_);
-  __ Bind(&string_patches_.back().label);
+void CodeGeneratorX86::RecordBootImageStringPatch(HLoadString* load_string) {
+  HX86ComputeBaseMethodAddress* method_address =
+      load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
+  boot_image_string_patches_.emplace_back(
+      method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
+  __ Bind(&boot_image_string_patches_.back().label);
 }
 
 Label* CodeGeneratorX86::NewStringBssEntryPatch(HLoadString* load_string) {
   DCHECK(!GetCompilerOptions().IsBootImage());
-  HX86ComputeBaseMethodAddress* address =
+  HX86ComputeBaseMethodAddress* method_address =
       load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
   string_bss_entry_patches_.emplace_back(
-      address, load_string->GetDexFile(), load_string->GetStringIndex().index_);
+      method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
   return &string_bss_entry_patches_.back().label;
 }
 
@@ -4661,8 +4657,10 @@
     ArenaVector<linker::LinkerPatch>* linker_patches) {
   for (const X86PcRelativePatchInfo& info : infos) {
     uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
-    linker_patches->push_back(Factory(
-        literal_offset, &info.dex_file, GetMethodAddressOffset(info.method_address), info.index));
+    linker_patches->push_back(Factory(literal_offset,
+                                      info.target_dex_file,
+                                      GetMethodAddressOffset(info.method_address),
+                                      info.offset_or_index));
   }
 }
 
@@ -4673,7 +4671,7 @@
       method_bss_entry_patches_.size() +
       boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
-      string_patches_.size() +
+      boot_image_string_patches_.size() +
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
@@ -4682,13 +4680,13 @@
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
         boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
     DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
         boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
@@ -6118,7 +6116,7 @@
                                               Handle<mirror::Class> handle) {
   ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
   // Add a patch entry and return the label.
-  jit_class_patches_.emplace_back(dex_file, type_index.index_);
+  jit_class_patches_.emplace_back(&dex_file, type_index.index_);
   PatchInfo<Label>* info = &jit_class_patches_.back();
   return &info->label;
 }
@@ -6160,7 +6158,7 @@
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
-      codegen_->RecordBootTypePatch(cls);
+      codegen_->RecordBootImageTypePatch(cls);
       break;
     }
     case HLoadClass::LoadKind::kBootImageAddress: {
@@ -6175,7 +6173,7 @@
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ movl(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
-      codegen_->RecordBootTypePatch(cls);
+      codegen_->RecordBootImageTypePatch(cls);
       // Extract the reference from the slot data, i.e. clear the hash bits.
       int32_t masked_hash = ClassTable::TableSlot::MaskHash(
           ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
@@ -6307,7 +6305,7 @@
                                                Handle<mirror::String> handle) {
   ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
   // Add a patch entry and return the label.
-  jit_string_patches_.emplace_back(dex_file, string_index.index_);
+  jit_string_patches_.emplace_back(&dex_file, string_index.index_);
   PatchInfo<Label>* info = &jit_string_patches_.back();
   return &info->label;
 }
@@ -6324,7 +6322,7 @@
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
-      codegen_->RecordBootStringPatch(load);
+      codegen_->RecordBootImageStringPatch(load);
       return;
     }
     case HLoadString::LoadKind::kBootImageAddress: {
@@ -6338,7 +6336,7 @@
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ movl(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
-      codegen_->RecordBootStringPatch(load);
+      codegen_->RecordBootImageStringPatch(load);
       return;
     }
     case HLoadString::LoadKind::kBssEntry: {
@@ -7830,13 +7828,13 @@
 
 void CodeGeneratorX86::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
   for (const PatchInfo<Label>& info : jit_string_patches_) {
-    StringReference string_reference(&info.dex_file, dex::StringIndex(info.index));
+    StringReference string_reference(info.target_dex_file, dex::StringIndex(info.offset_or_index));
     uint64_t index_in_table = GetJitStringRootIndex(string_reference);
     PatchJitRootUse(code, roots_data, info, index_in_table);
   }
 
   for (const PatchInfo<Label>& info : jit_class_patches_) {
-    TypeReference type_reference(&info.dex_file, dex::TypeIndex(info.index));
+    TypeReference type_reference(info.target_dex_file, dex::TypeIndex(info.offset_or_index));
     uint64_t index_in_table = GetJitClassRootIndex(type_reference);
     PatchJitRootUse(code, roots_data, info, index_in_table);
   }
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 0082853..51e5bca 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -414,12 +414,11 @@
   void GenerateVirtualCall(
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
-  void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
-  Label* NewMethodBssEntryPatch(HX86ComputeBaseMethodAddress* method_address,
-                                MethodReference target_method);
-  void RecordBootTypePatch(HLoadClass* load_class);
+  void RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke);
+  void RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke);
+  void RecordBootImageTypePatch(HLoadClass* load_class);
   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
-  void RecordBootStringPatch(HLoadString* load_string);
+  void RecordBootImageStringPatch(HLoadString* load_string);
   Label* NewStringBssEntryPatch(HLoadString* load_string);
   Label* NewJitRootStringPatch(const DexFile& dex_file,
                                dex::StringIndex string_index,
@@ -610,7 +609,7 @@
  private:
   struct X86PcRelativePatchInfo : PatchInfo<Label> {
     X86PcRelativePatchInfo(HX86ComputeBaseMethodAddress* address,
-                           const DexFile& target_dex_file,
+                           const DexFile* target_dex_file,
                            uint32_t target_index)
         : PatchInfo(target_dex_file, target_index),
           method_address(address) {}
@@ -641,7 +640,7 @@
   // Type patch locations for kBssEntry.
   ArenaDeque<X86PcRelativePatchInfo> type_bss_entry_patches_;
   // String patch locations; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<X86PcRelativePatchInfo> string_patches_;
+  ArenaDeque<X86PcRelativePatchInfo> boot_image_string_patches_;
   // String patch locations for kBssEntry.
   ArenaDeque<X86PcRelativePatchInfo> string_bss_entry_patches_;
 
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index ae35ab5..7be3605 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -993,7 +993,7 @@
       DCHECK(GetCompilerOptions().IsBootImage());
       __ leal(temp.AsRegister<CpuRegister>(),
               Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
-      RecordBootMethodPatch(invoke);
+      RecordBootImageMethodPatch(invoke);
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress());
@@ -1001,9 +1001,7 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
       __ movq(temp.AsRegister<CpuRegister>(),
               Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
-      // Bind a new fixup label at the end of the "movl" insn.
-      __ Bind(NewMethodBssEntryPatch(
-          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())));
+      RecordMethodBssEntryPatch(invoke);
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -1061,38 +1059,39 @@
   RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
 }
 
-void CodeGeneratorX86_64::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) {
-  boot_image_method_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
-                                          invoke->GetTargetMethod().index);
+void CodeGeneratorX86_64::RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke) {
+  boot_image_method_patches_.emplace_back(
+      invoke->GetTargetMethod().dex_file, invoke->GetTargetMethod().index);
   __ Bind(&boot_image_method_patches_.back().label);
 }
 
-Label* CodeGeneratorX86_64::NewMethodBssEntryPatch(MethodReference target_method) {
-  // Add a patch entry and return the label.
-  method_bss_entry_patches_.emplace_back(*target_method.dex_file, target_method.index);
-  return &method_bss_entry_patches_.back().label;
+void CodeGeneratorX86_64::RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke) {
+  method_bss_entry_patches_.emplace_back(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex());
+  __ Bind(&method_bss_entry_patches_.back().label);
 }
 
-void CodeGeneratorX86_64::RecordBootTypePatch(HLoadClass* load_class) {
-  boot_image_type_patches_.emplace_back(load_class->GetDexFile(),
-                                        load_class->GetTypeIndex().index_);
+void CodeGeneratorX86_64::RecordBootImageTypePatch(HLoadClass* load_class) {
+  boot_image_type_patches_.emplace_back(
+      &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   __ Bind(&boot_image_type_patches_.back().label);
 }
 
 Label* CodeGeneratorX86_64::NewTypeBssEntryPatch(HLoadClass* load_class) {
-  type_bss_entry_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
+  type_bss_entry_patches_.emplace_back(
+      &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   return &type_bss_entry_patches_.back().label;
 }
 
-void CodeGeneratorX86_64::RecordBootStringPatch(HLoadString* load_string) {
-  string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex().index_);
-  __ Bind(&string_patches_.back().label);
+void CodeGeneratorX86_64::RecordBootImageStringPatch(HLoadString* load_string) {
+  boot_image_string_patches_.emplace_back(
+      &load_string->GetDexFile(), load_string->GetStringIndex().index_);
+  __ Bind(&boot_image_string_patches_.back().label);
 }
 
 Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) {
   DCHECK(!GetCompilerOptions().IsBootImage());
   string_bss_entry_patches_.emplace_back(
-      load_string->GetDexFile(), load_string->GetStringIndex().index_);
+      &load_string->GetDexFile(), load_string->GetStringIndex().index_);
   return &string_bss_entry_patches_.back().label;
 }
 
@@ -1107,7 +1106,7 @@
   for (const PatchInfo<Label>& info : infos) {
     uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
     linker_patches->push_back(
-        Factory(literal_offset, &info.dex_file, info.label.Position(), info.index));
+        Factory(literal_offset, info.target_dex_file, info.label.Position(), info.offset_or_index));
   }
 }
 
@@ -1118,7 +1117,7 @@
       method_bss_entry_patches_.size() +
       boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
-      string_patches_.size() +
+      boot_image_string_patches_.size() +
       string_bss_entry_patches_.size();
   linker_patches->reserve(size);
   if (GetCompilerOptions().IsBootImage()) {
@@ -1127,13 +1126,13 @@
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
         boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
-        string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   } else {
     DCHECK(boot_image_method_patches_.empty());
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
         boot_image_type_patches_, linker_patches);
     EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
-        string_patches_, linker_patches);
+        boot_image_string_patches_, linker_patches);
   }
   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
       method_bss_entry_patches_, linker_patches);
@@ -1231,7 +1230,7 @@
         method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
-        string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+        boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
         jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -5529,7 +5528,7 @@
                                                  Handle<mirror::Class> handle) {
   ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
   // Add a patch entry and return the label.
-  jit_class_patches_.emplace_back(dex_file, type_index.index_);
+  jit_class_patches_.emplace_back(&dex_file, type_index.index_);
   PatchInfo<Label>* info = &jit_class_patches_.back();
   return &info->label;
 }
@@ -5570,7 +5569,7 @@
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
-      codegen_->RecordBootTypePatch(cls);
+      codegen_->RecordBootImageTypePatch(cls);
       break;
     case HLoadClass::LoadKind::kBootImageAddress: {
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
@@ -5583,7 +5582,7 @@
     case HLoadClass::LoadKind::kBootImageClassTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
-      codegen_->RecordBootTypePatch(cls);
+      codegen_->RecordBootImageTypePatch(cls);
       // Extract the reference from the slot data, i.e. clear the hash bits.
       int32_t masked_hash = ClassTable::TableSlot::MaskHash(
           ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
@@ -5694,7 +5693,7 @@
                                                   Handle<mirror::String> handle) {
   ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
   // Add a patch entry and return the label.
-  jit_string_patches_.emplace_back(dex_file, string_index.index_);
+  jit_string_patches_.emplace_back(&dex_file, string_index.index_);
   PatchInfo<Label>* info = &jit_string_patches_.back();
   return &info->label;
 }
@@ -5710,7 +5709,7 @@
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
-      codegen_->RecordBootStringPatch(load);
+      codegen_->RecordBootImageStringPatch(load);
       return;
     }
     case HLoadString::LoadKind::kBootImageAddress: {
@@ -5723,7 +5722,7 @@
     case HLoadString::LoadKind::kBootImageInternTable: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
       __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
-      codegen_->RecordBootStringPatch(load);
+      codegen_->RecordBootImageStringPatch(load);
       return;
     }
     case HLoadString::LoadKind::kBssEntry: {
@@ -7160,13 +7159,13 @@
 
 void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
   for (const PatchInfo<Label>& info : jit_string_patches_) {
-    StringReference string_reference(&info.dex_file, dex::StringIndex(info.index));
+    StringReference string_reference(info.target_dex_file, dex::StringIndex(info.offset_or_index));
     uint64_t index_in_table = GetJitStringRootIndex(string_reference);
     PatchJitRootUse(code, roots_data, info, index_in_table);
   }
 
   for (const PatchInfo<Label>& info : jit_class_patches_) {
-    TypeReference type_reference(&info.dex_file, dex::TypeIndex(info.index));
+    TypeReference type_reference(info.target_dex_file, dex::TypeIndex(info.offset_or_index));
     uint64_t index_in_table = GetJitClassRootIndex(type_reference);
     PatchJitRootUse(code, roots_data, info, index_in_table);
   }
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index e86123e..1079e94 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -410,11 +410,11 @@
   void GenerateVirtualCall(
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
-  void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
-  Label* NewMethodBssEntryPatch(MethodReference target_method);
-  void RecordBootTypePatch(HLoadClass* load_class);
+  void RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke);
+  void RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke);
+  void RecordBootImageTypePatch(HLoadClass* load_class);
   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
-  void RecordBootStringPatch(HLoadString* load_string);
+  void RecordBootImageStringPatch(HLoadString* load_string);
   Label* NewStringBssEntryPatch(HLoadString* load_string);
   Label* NewJitRootStringPatch(const DexFile& dex_file,
                                dex::StringIndex string_index,
@@ -613,7 +613,7 @@
   // Type patch locations for kBssEntry.
   ArenaDeque<PatchInfo<Label>> type_bss_entry_patches_;
   // String patch locations; type depends on configuration (intern table or boot image PIC).
-  ArenaDeque<PatchInfo<Label>> string_patches_;
+  ArenaDeque<PatchInfo<Label>> boot_image_string_patches_;
   // String patch locations for kBssEntry.
   ArenaDeque<PatchInfo<Label>> string_bss_entry_patches_;
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 43ca2cf..f91d37b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4567,7 +4567,7 @@
                                                kFieldClinitCheckRequirementSize>;
 
   // Cached values of the resolved method, to avoid needing the mutator lock.
-  MethodReference target_method_;
+  const MethodReference target_method_;
   DispatchInfo dispatch_info_;
 };
 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs);
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index ab06ddd..d1272c9 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -152,7 +152,7 @@
         "libartd-compiler",
         "libartd-dexlayout",
         "libartd",
-        "libdexfile",
+        "libdexfiled",
         "libbase",
         "liblz4",
         "libsigchain",
@@ -185,6 +185,7 @@
         "libart-compiler",
         "libart-dexlayout",
         "libart",
+        "libdexfile",
         "libvixl-arm",
         "libvixl-arm64",
     ] + art_static_dependencies,
@@ -216,6 +217,7 @@
         "libartd-compiler",
         "libartd-dexlayout",
         "libartd",
+        "libdexfiled",
         "libvixld-arm",
         "libvixld-arm64",
     ] + art_static_dependencies,
@@ -246,6 +248,7 @@
         "libbase",
         "liblz4",
         "libsigchain",
+        "libziparchive",
     ],
     static_libs: [
         "libartd-dex2oat",
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 64db7be..b5c5e45 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -456,6 +456,9 @@
   UsageError("  --deduplicate-code=true|false: enable|disable code deduplication. Deduplicated");
   UsageError("      code will have an arbitrary symbol tagged with [DEDUPED].");
   UsageError("");
+  UsageError("  --copying-dex-files=true|false: enable|disable copying the dex files into the");
+  UsageError("      output vdex.");
+  UsageError("");
   UsageError("  --compilation-reason=<string>: optional metadata specifying the reason for");
   UsageError("      compiling the apk. If specified, the string will be embedded verbatim in");
   UsageError("      the key value store of the oat file.");
@@ -1232,6 +1235,7 @@
     AssignTrueIfExists(args, M::Host, &is_host_);
     AssignTrueIfExists(args, M::AvoidStoringInvocation, &avoid_storing_invocation_);
     AssignTrueIfExists(args, M::MultiImage, &multi_image_);
+    AssignIfExists(args, M::CopyDexFiles, &copy_dex_files_);
 
     if (args.Exists(M::ForceDeterminism)) {
       if (!SupportsDeterministicCompilation()) {
@@ -1425,13 +1429,10 @@
         LOG(INFO) << "No " << VdexFile::kVdexNameInDmFile << " file in DexMetadata archive. "
                   << "Not doing fast verification.";
       } else {
-        std::unique_ptr<MemMap> input_file;
-        if (zip_entry->IsUncompressed()) {
-          input_file.reset(zip_entry->MapDirectlyFromFile(VdexFile::kVdexNameInDmFile, &error_msg));
-        } else {
-          input_file.reset(zip_entry->ExtractToMemMap(
-              kDexMetadata, VdexFile::kVdexNameInDmFile, &error_msg));
-        }
+        std::unique_ptr<MemMap> input_file(zip_entry->MapDirectlyOrExtract(
+            VdexFile::kVdexNameInDmFile,
+            kDexMetadata,
+            &error_msg));
         if (input_file == nullptr) {
           LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
         } else {
@@ -1618,6 +1619,7 @@
             key_value_store_.get(),
             verify,
             update_input_vdex_,
+            copy_dex_files_,
             &opened_dex_files_map,
             &opened_dex_files)) {
           return dex2oat::ReturnCode::kOther;
@@ -2918,6 +2920,9 @@
   // Whether the given input vdex is also the output.
   bool update_input_vdex_ = false;
 
+  // By default, copy the dex to the vdex file.
+  bool copy_dex_files_ = true;
+
   // The reason for invoking the compiler.
   std::string compilation_reason_;
 
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 4b6f8a4..1ef100d 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -233,6 +233,11 @@
           .IntoKey(M::VeryLargeAppThreshold)
       .Define("--force-determinism")
           .IntoKey(M::ForceDeterminism)
+      .Define("--copy-dex-files=_")
+          .WithType<bool>()
+          .WithValueMap({{"true", false},
+                         {"false", false}})
+          .IntoKey(M::CopyDexFiles)
       .Define("--classpath-dir=_")
           .WithType<std::string>()
           .IntoKey(M::ClasspathDir)
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index a1646aa..a9d349b 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -74,6 +74,7 @@
 DEX2OAT_OPTIONS_KEY (Unit,                           DumpTiming)
 DEX2OAT_OPTIONS_KEY (Unit,                           DumpPasses)
 DEX2OAT_OPTIONS_KEY (Unit,                           DumpStats)
+DEX2OAT_OPTIONS_KEY (bool,                           CopyDexFiles)
 DEX2OAT_OPTIONS_KEY (Unit,                           AvoidStoringInvocation)
 DEX2OAT_OPTIONS_KEY (std::string,                    SwapFile)
 DEX2OAT_OPTIONS_KEY (int,                            SwapFileFd)
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 4ac8e6a..12cfd24 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -41,6 +41,8 @@
 #include "oat.h"
 #include "oat_file.h"
 #include "utils.h"
+#include "vdex_file.h"
+#include "ziparchive/zip_writer.h"
 
 namespace art {
 
@@ -1781,4 +1783,90 @@
   ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
 }
 
+TEST_F(Dex2oatTest, DontExtract) {
+  std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
+  std::string error_msg;
+  const std::string out_dir = GetScratchDir();
+  const std::string dex_location = dex->GetLocation();
+  const std::string odex_location = out_dir + "/base.oat";
+  const std::string vdex_location = out_dir + "/base.vdex";
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::Filter::kVerify,
+                      { "--copy-dex-files=false" },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [](const OatFile&) {
+                      });
+  {
+    // Check the vdex doesn't have dex.
+    std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
+                                                  /*writable*/ false,
+                                                  /*low_4gb*/ false,
+                                                  /*unquicken*/ false,
+                                                  &error_msg));
+    ASSERT_TRUE(vdex != nullptr);
+    EXPECT_EQ(vdex->GetHeader().GetDexSize(), 0u) << output_;
+  }
+  std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                   odex_location.c_str(),
+                                                   nullptr,
+                                                   nullptr,
+                                                   false,
+                                                   /*low_4gb*/ false,
+                                                   dex_location.c_str(),
+                                                   &error_msg));
+  ASSERT_TRUE(odex_file != nullptr) << dex_location;
+  std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
+  ASSERT_EQ(oat_dex_files.size(), 1u);
+  // Verify that the oat file can still open the dex files.
+  for (const OatDexFile* oat_dex : oat_dex_files) {
+    std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
+    ASSERT_TRUE(dex_file != nullptr) << error_msg;
+  }
+  // Create a dm file and use it to verify.
+  // Add produced artifacts to a zip file that doesn't contain the classes.dex.
+  ScratchFile dm_file;
+  {
+    std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_location.c_str()));
+    ASSERT_TRUE(vdex_file != nullptr);
+    ASSERT_GT(vdex_file->GetLength(), 0u);
+    FILE* file = fdopen(dm_file.GetFd(), "w+b");
+    ZipWriter writer(file);
+    auto write_all_bytes = [&](File* file) {
+      std::unique_ptr<uint8_t[]> bytes(new uint8_t[file->GetLength()]);
+      ASSERT_TRUE(file->ReadFully(&bytes[0], file->GetLength()));
+      ASSERT_GE(writer.WriteBytes(&bytes[0], file->GetLength()), 0);
+    };
+    // Add vdex to zip.
+    writer.StartEntry(VdexFile::kVdexNameInDmFile, ZipWriter::kCompress);
+    write_all_bytes(vdex_file.get());
+    writer.FinishEntry();
+    writer.Finish();
+    ASSERT_EQ(dm_file.GetFile()->Flush(), 0);
+  }
+
+  // Generate a quickened dex by using the input dm file to verify.
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::Filter::kQuicken,
+                      { "--dump-timings", "--dm-file=" + dm_file.GetFilename() },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [](const OatFile& o) {
+                        CHECK(o.ContainsDexCode());
+                      });
+  if (!kIsTargetBuild) {
+    // The output_ variable is not correctly set for target, TODO: investigate.
+    std::istringstream iss(output_);
+    std::string line;
+    bool found_fast_verify = false;
+    const std::string kFastVerifyString = "Fast Verify";
+    while (std::getline(iss, line) && !found_fast_verify) {
+      found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos;
+    }
+    EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_;
+  }
+}
+
 }  // namespace art
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 62519fc..303c873 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -276,6 +276,7 @@
             &key_value_store,
             /* verify */ false,           // Dex files may be dex-to-dex-ed, don't verify.
             /* update_input_vdex */ false,
+            /* extract_dex_files */ true,
             &cur_opened_dex_files_maps,
             &cur_opened_dex_files);
         ASSERT_TRUE(dex_files_ok);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 7d8065e..09f9010 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -368,7 +368,7 @@
     compiler_driver_(nullptr),
     image_writer_(nullptr),
     compiling_boot_image_(compiling_boot_image),
-    only_contains_uncompressed_zip_entries_(false),
+    extract_dex_files_into_vdex_(true),
     dex_files_(nullptr),
     vdex_size_(0u),
     vdex_dex_files_offset_(0u),
@@ -643,6 +643,7 @@
     SafeMap<std::string, std::string>* key_value_store,
     bool verify,
     bool update_input_vdex,
+    bool copy_dex_files,
     /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map,
     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
   CHECK(write_state_ == WriteState::kAddingDexFileSources);
@@ -669,7 +670,7 @@
   std::unique_ptr<BufferedOutputStream> vdex_out =
       std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
   // Write DEX files into VDEX, mmap and open them.
-  if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
+  if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex, copy_dex_files) ||
       !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
     return false;
   }
@@ -2749,7 +2750,7 @@
 };
 
 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
-  if (only_contains_uncompressed_zip_entries_) {
+  if (!extract_dex_files_into_vdex_) {
     // Nothing to write. Leave `vdex_size_` untouched and unaligned.
     vdex_quickening_info_offset_ = vdex_size_;
     size_quickening_info_alignment_ = 0;
@@ -3339,25 +3340,32 @@
   return true;
 }
 
-bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
+bool OatWriter::WriteDexFiles(OutputStream* out,
+                              File* file,
+                              bool update_input_vdex,
+                              bool copy_dex_files) {
   TimingLogger::ScopedTiming split("Write Dex files", timings_);
 
   vdex_dex_files_offset_ = vdex_size_;
 
-  only_contains_uncompressed_zip_entries_ = true;
-  for (OatDexFile& oat_dex_file : oat_dex_files_) {
-    if (!oat_dex_file.source_.IsZipEntry()) {
-      only_contains_uncompressed_zip_entries_ = false;
-      break;
-    }
-    ZipEntry* entry = oat_dex_file.source_.GetZipEntry();
-    if (!entry->IsUncompressed() || !entry->IsAlignedToDexHeader()) {
-      only_contains_uncompressed_zip_entries_ = false;
-      break;
+  extract_dex_files_into_vdex_ = copy_dex_files;
+  // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed.
+  if (extract_dex_files_into_vdex_) {
+    extract_dex_files_into_vdex_ = false;
+    for (OatDexFile& oat_dex_file : oat_dex_files_) {
+      if (!oat_dex_file.source_.IsZipEntry()) {
+        extract_dex_files_into_vdex_ = true;
+        break;
+      }
+      ZipEntry* entry = oat_dex_file.source_.GetZipEntry();
+      if (!entry->IsUncompressed() || !entry->IsAlignedToDexHeader()) {
+        extract_dex_files_into_vdex_ = true;
+        break;
+      }
     }
   }
 
-  if (!only_contains_uncompressed_zip_entries_) {
+  if (extract_dex_files_into_vdex_) {
     // Write dex files.
     for (OatDexFile& oat_dex_file : oat_dex_files_) {
       if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
@@ -3823,13 +3831,13 @@
     return true;
   }
 
-  if (only_contains_uncompressed_zip_entries_) {
+  if (!extract_dex_files_into_vdex_) {
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     std::vector<std::unique_ptr<MemMap>> maps;
     for (OatDexFile& oat_dex_file : oat_dex_files_) {
       std::string error_msg;
-      MemMap* map = oat_dex_file.source_.GetZipEntry()->MapDirectlyFromFile(
-          oat_dex_file.dex_file_location_data_, &error_msg);
+      MemMap* map = oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract(
+          oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg);
       if (map == nullptr) {
         LOG(ERROR) << error_msg;
         return false;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 7edb032..6a7e1e4 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -168,6 +168,7 @@
   // This is generally the case, and should only be false for tests.
   // If `update_input_vdex` is true, then this method won't actually write the dex files,
   // and the compiler will just re-use the existing vdex file.
+  // If `copy_dex_files` is true, copy the input dex files into the vdex file.
   bool WriteAndOpenDexFiles(File* vdex_file,
                             OutputStream* oat_rodata,
                             InstructionSet instruction_set,
@@ -175,6 +176,7 @@
                             SafeMap<std::string, std::string>* key_value_store,
                             bool verify,
                             bool update_input_vdex,
+                            bool copy_dex_files,
                             /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map,
                             /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
   bool WriteQuickeningInfo(OutputStream* vdex_out);
@@ -283,7 +285,10 @@
 
   // If `update_input_vdex` is true, then this method won't actually write the dex files,
   // and the compiler will just re-use the existing vdex file.
-  bool WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex);
+  bool WriteDexFiles(OutputStream* out,
+                     File* file,
+                     bool update_input_vdex,
+                     bool copy_dex_files);
   bool WriteDexFile(OutputStream* out,
                     File* file,
                     OatDexFile* oat_dex_file,
@@ -341,7 +346,7 @@
   bool MayHaveCompiledMethods() const;
 
   bool VdexWillContainDexFiles() const {
-    return dex_files_ != nullptr && !only_contains_uncompressed_zip_entries_;
+    return dex_files_ != nullptr && extract_dex_files_into_vdex_;
   }
 
   // Find the address of the GcRoot<String> in the InternTable for a boot image string.
@@ -375,8 +380,8 @@
   const CompilerDriver* compiler_driver_;
   ImageWriter* image_writer_;
   const bool compiling_boot_image_;
-  // Whether the dex files being compiled are all uncompressed in the APK.
-  bool only_contains_uncompressed_zip_entries_;
+  // Whether the dex files being compiled are going to be extracted to the vdex.
+  bool extract_dex_files_into_vdex_;
 
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index cd6ca51..6dd8e19 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -190,15 +190,17 @@
     OutputStream* oat_rodata = elf_writer->StartRoData();
     std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps;
     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-    if (!oat_writer.WriteAndOpenDexFiles(vdex_file,
-                                         oat_rodata,
-                                         compiler_driver_->GetInstructionSet(),
-                                         compiler_driver_->GetInstructionSetFeatures(),
-                                         &key_value_store,
-                                         verify,
-                                         /* update_input_vdex */ false,
-                                         &opened_dex_files_maps,
-                                         &opened_dex_files)) {
+    if (!oat_writer.WriteAndOpenDexFiles(
+        vdex_file,
+        oat_rodata,
+        compiler_driver_->GetInstructionSet(),
+        compiler_driver_->GetInstructionSetFeatures(),
+        &key_value_store,
+        verify,
+        /* update_input_vdex */ false,
+        compiler_driver_->GetCompilerOptions().GetCompilerFilter(),
+        &opened_dex_files_maps,
+        &opened_dex_files)) {
       return false;
     }
 
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index f6b7a6b..eca0844 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -45,6 +45,7 @@
     host_supported: true,
     device_supported: false,
     static_libs: [
+        "libdexfile",
         "libbase",
     ] + art_static_dependencies,
     target: {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 8778b12..61a1209 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -34,19 +34,14 @@
 
 #include "dexdump.h"
 
-#include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
 
-#include <iostream>
 #include <memory>
 #include <sstream>
 #include <vector>
 
+#include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
 
@@ -1879,34 +1874,6 @@
   }
 }
 
-static bool openAndMapFile(const char* fileName,
-                           const uint8_t** base,
-                           size_t* size,
-                           std::string* error_msg) {
-  int fd = open(fileName, O_RDONLY);
-  if (fd < 0) {
-    *error_msg = "open failed";
-    return false;
-  }
-  struct stat st;
-  if (fstat(fd, &st) < 0) {
-    *error_msg = "stat failed";
-    return false;
-  }
-  *size = st.st_size;
-  if (*size == 0) {
-    *error_msg = "size == 0";
-    return false;
-  }
-  void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
-  if (addr == MAP_FAILED) {
-    *error_msg = "mmap failed";
-    return false;
-  }
-  *base = reinterpret_cast<const uint8_t*>(addr);
-  return true;
-}
-
 /*
  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
  */
@@ -1918,17 +1885,22 @@
   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   // all of which are Zip archives with "classes.dex" inside.
   const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
-  const uint8_t* base = nullptr;
-  size_t size = 0;
-  std::string error_msg;
-  if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
-    LOG(ERROR) << error_msg;
+  std::string content;
+  // TODO: add an api to android::base to read a std::vector<uint8_t>.
+  if (!android::base::ReadFileToString(fileName, &content)) {
+    LOG(ERROR) << "ReadFileToString failed";
     return -1;
   }
   const DexFileLoader dex_file_loader;
+  std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!dex_file_loader.OpenAll(
-        base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
+                               content.size(),
+                               fileName,
+                               /*verify*/ true,
+                               kVerifyChecksum,
+                               &error_msg,
+                               &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
     LOG(ERROR) << error_msg;
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 3ea7f4b..bea61d0 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -27,7 +27,6 @@
     ],
     export_include_dirs: ["."],
     shared_libs: [
-        "libdexfile",
         "libbase",
     ],
     static_libs: ["libz"],
@@ -36,7 +35,10 @@
 art_cc_library {
     name: "libart-dexlayout",
     defaults: ["libart-dexlayout-defaults"],
-    shared_libs: ["libart"],
+    shared_libs: [
+        "libart",
+        "libdexfile",
+    ],
 
     pgo: {
         instrumentation: true,
@@ -51,7 +53,10 @@
       "libart-dexlayout-defaults",
       "art_debug_defaults",
     ],
-    shared_libs: ["libartd"],
+    shared_libs: [
+        "libartd",
+        "libdexfiled",
+    ],
 }
 
 cc_defaults {
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 31a146d..6a50258 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -23,15 +23,11 @@
  * List all methods in all concrete classes in one or more DEX files.
  */
 
-#include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 
 #include "dex/code_item_accessors-inl.h"
@@ -170,34 +166,6 @@
   }
 }
 
-static bool openAndMapFile(const char* fileName,
-                           const uint8_t** base,
-                           size_t* size,
-                           std::string* error_msg) {
-  int fd = open(fileName, O_RDONLY);
-  if (fd < 0) {
-    *error_msg = "open failed";
-    return false;
-  }
-  struct stat st;
-  if (fstat(fd, &st) < 0) {
-    *error_msg = "stat failed";
-    return false;
-  }
-  *size = st.st_size;
-  if (*size == 0) {
-    *error_msg = "size == 0";
-    return false;
-  }
-  void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
-  if (addr == MAP_FAILED) {
-    *error_msg = "mmap failed";
-    return false;
-  }
-  *base = reinterpret_cast<const uint8_t*>(addr);
-  return true;
-}
-
 /*
  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
  */
@@ -205,17 +173,22 @@
   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   // all of which are Zip archives with "classes.dex" inside.
   static constexpr bool kVerifyChecksum = true;
-  const uint8_t* base = nullptr;
-  size_t size = 0;
-  std::string error_msg;
-  if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
-    LOG(ERROR) << error_msg;
+  std::string content;
+  // TODO: add an api to android::base to read a std::vector<uint8_t>.
+  if (!android::base::ReadFileToString(fileName, &content)) {
+    LOG(ERROR) << "ReadFileToString failed";
     return -1;
   }
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::string error_msg;
   const DexFileLoader dex_file_loader;
-  if (!dex_file_loader.OpenAll(
-        base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
+                               content.size(),
+                               fileName,
+                               /*verify*/ true,
+                               kVerifyChecksum,
+                               &error_msg,
+                               &dex_files)) {
     LOG(ERROR) << error_msg;
     return -1;
   }
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index bcf2bdb..90c603f 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -93,6 +93,14 @@
     },
 }
 
+art_cc_library {
+    name: "libdexfiled",
+    defaults: [
+        "art_debug_defaults",
+        "libdexfile_defaults",
+    ],
+}
+
 art_cc_test {
     name: "art_libdexfile_tests",
     defaults: [
diff --git a/libdexfile/dex/base64_test_util.h b/libdexfile/dex/base64_test_util.h
index 683e429..5d73759 100644
--- a/libdexfile/dex/base64_test_util.h
+++ b/libdexfile/dex/base64_test_util.h
@@ -17,13 +17,14 @@
 #ifndef ART_LIBDEXFILE_DEX_BASE64_TEST_UTIL_H_
 #define ART_LIBDEXFILE_DEX_BASE64_TEST_UTIL_H_
 
-#include <base/logging.h>
 #include <stdint.h>
 #include <stdlib.h>
 
 #include <memory>
 #include <vector>
 
+#include <android-base/logging.h>
+
 namespace art {
 
 static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
diff --git a/libdexfile/dex/compact_dex_debug_info_test.cc b/libdexfile/dex/compact_dex_debug_info_test.cc
index 3267612..7911a86 100644
--- a/libdexfile/dex/compact_dex_debug_info_test.cc
+++ b/libdexfile/dex/compact_dex_debug_info_test.cc
@@ -16,7 +16,7 @@
 
 #include <vector>
 
-#include "base/logging.h"
+#include <android-base/logging.h>
 #include "dex/compact_dex_debug_info.h"
 #include "gtest/gtest.h"
 
@@ -74,7 +74,7 @@
                                         /*out*/ &table_offset);
   EXPECT_LT(sorted_data.size(), data.size());
   {
-    ScopedLogSeverity sls(LogSeverity::INFO);
+    android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO);
     LOG(INFO) << "raw size " << before_size
               << " table size " << data.size()
               << " sorted table size " << sorted_data.size();
diff --git a/libdexfile/dex/compact_dex_level.h b/libdexfile/dex/compact_dex_level.h
index 2325ac2..599ec4d 100644
--- a/libdexfile/dex/compact_dex_level.h
+++ b/libdexfile/dex/compact_dex_level.h
@@ -19,7 +19,6 @@
 
 #include <string>
 
-#include "base/macros.h"
 #include "dex_file.h"
 
 namespace art {
diff --git a/runtime/dex_cache_resolved_classes.h b/libdexfile/dex/dex_cache_resolved_classes.h
similarity index 93%
rename from runtime/dex_cache_resolved_classes.h
rename to libdexfile/dex/dex_cache_resolved_classes.h
index ca6afc5..4c9acbf 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/libdexfile/dex/dex_cache_resolved_classes.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_DEX_CACHE_RESOLVED_CLASSES_H_
-#define ART_RUNTIME_DEX_CACHE_RESOLVED_CLASSES_H_
+#ifndef ART_LIBDEXFILE_DEX_DEX_CACHE_RESOLVED_CLASSES_H_
+#define ART_LIBDEXFILE_DEX_DEX_CACHE_RESOLVED_CLASSES_H_
 
 #include <string>
 #include <unordered_set>
@@ -90,4 +90,4 @@
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_DEX_CACHE_RESOLVED_CLASSES_H_
+#endif  // ART_LIBDEXFILE_DEX_DEX_CACHE_RESOLVED_CLASSES_H_
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index b424b50..c86e879 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -17,7 +17,6 @@
 #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
 #define ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
 
-#include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/stringpiece.h"
 #include "compact_dex_file.h"
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 18eb903..6a704c1 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -45,6 +45,21 @@
 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
 static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
 
+void DexFile::UnHideAccessFlags(ClassDataItemIterator& class_it) {
+  uint8_t* data = const_cast<uint8_t*>(class_it.DataPointer());
+  uint32_t new_flag = class_it.GetMemberAccessFlags();
+  bool is_method = class_it.IsAtMethod();
+  // Go back 1 uleb to start.
+  data = ReverseSearchUnsignedLeb128(data);
+  if (is_method) {
+    // Methods have another uleb field before the access flags
+    data = ReverseSearchUnsignedLeb128(data);
+  }
+  DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)),
+            new_flag);
+  UpdateUnsignedLeb128(data, new_flag);
+}
+
 uint32_t DexFile::CalculateChecksum() const {
   return CalculateChecksum(Begin(), Size());
 }
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index a38e76c..a62ab62 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -35,6 +35,7 @@
 
 namespace art {
 
+class ClassDataItemIterator;
 class CompactDexFile;
 enum InvokeType : uint32_t;
 class MemMap;
@@ -1000,6 +1001,9 @@
     return container_.get();
   }
 
+  // Changes the dex file pointed to by class_it to not have any hiddenapi flags.
+  static void UnHideAccessFlags(ClassDataItemIterator& class_it);
+
  protected:
   // First Dex format version supporting default methods.
   static const uint32_t kDefaultMethodsVersion = 37;
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index c93c172..012100d 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -51,7 +51,7 @@
         "libartd",
         "libartd-compiler",
         "libartd-disassembler",
-        "libdexfile",
+        "libdexfiled",
         "libbase",
     ],
 }
@@ -76,6 +76,7 @@
     ],
     static_libs: [
         "libart",
+        "libdexfile",
         "libart-compiler",
         "libart-disassembler",
         "libvixl-arm",
@@ -106,6 +107,7 @@
     ],
     static_libs: [
         "libartd",
+        "libdexfiled",
         "libartd-compiler",
         "libartd-disassembler",
         "libvixld-arm",
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index 1500bca..1553b78 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -58,7 +58,6 @@
         "libopenjdkjvmti_headers",
     ],
     shared_libs: [
-        "libdexfile",
         "libbase",
     ],
 }
@@ -70,6 +69,7 @@
         "libart",
         "libart-compiler",
         "libart-dexlayout",
+        "libdexfile",
     ],
 }
 
@@ -83,5 +83,6 @@
         "libartd",
         "libartd-compiler",
         "libartd-dexlayout",
+        "libdexfiled",
     ],
 }
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 427d87e..90c6449 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -40,6 +40,7 @@
 #include "dex/compact_dex_level.h"
 #include "dex_to_dex_decompiler.h"
 #include "dexlayout.h"
+#include "leb128.h"
 #include "oat_file.h"
 #include "vdex_file.h"
 
@@ -50,21 +51,41 @@
       dex_file->CalculateChecksum();
 }
 
-static void DoDexUnquicken(const art::DexFile& new_dex_file,
-                           const art::DexFile& original_dex_file) {
+static void UnhideApis(const art::DexFile& target_dex_file) {
+  for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
+    const uint8_t* class_data = target_dex_file.GetClassData(target_dex_file.GetClassDef(i));
+    if (class_data != nullptr) {
+      for (art::ClassDataItemIterator class_it(target_dex_file, class_data);
+           class_it.HasNext();
+           class_it.Next()) {
+        art::DexFile::UnHideAccessFlags(class_it);
+      }
+    }
+  }
+}
+
+static const art::VdexFile* GetVdex(const art::DexFile& original_dex_file) {
   const art::OatDexFile* oat_dex = original_dex_file.GetOatDexFile();
   if (oat_dex == nullptr) {
-    return;
+    return nullptr;
   }
   const art::OatFile* oat_file = oat_dex->GetOatFile();
   if (oat_file == nullptr) {
-    return;
+    return nullptr;
   }
-  const art::VdexFile* vdex = oat_file->GetVdexFile();
-  if (vdex == nullptr) {
-    return;
+  return oat_file->GetVdexFile();
+}
+
+static void DoDexUnquicken(const art::DexFile& new_dex_file,
+                           const art::DexFile& original_dex_file) {
+  const art::VdexFile* vdex = GetVdex(original_dex_file);
+  if (vdex != nullptr) {
+    vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
+  } else {
+    // The dex file isn't quickened since it is being used directly. We might still have hiddenapis
+    // so we need to get rid of those.
+    UnhideApis(new_dex_file);
   }
-  vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
 }
 
 static void DCheckVerifyDexFile(const art::DexFile& dex) {
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index d9cefee..4900f17 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -357,6 +357,65 @@
   return true;
 }
 
+static bool VerifySymlink(const std::string& intended_target, const std::string& link_name) {
+  std::string actual_target;
+  if (!android::base::Readlink(link_name, &actual_target)) {
+    PLOG(ERROR) << "Readlink on " << link_name << " failed.";
+    return false;
+  }
+  return actual_target == intended_target;
+}
+
+static bool VerifyVdexAndOatSymlinks(const std::string& input_image_filename,
+                                     const std::string& output_image_filename) {
+  return VerifySymlink(ImageHeader::GetVdexLocationFromImageLocation(input_image_filename),
+                       ImageHeader::GetVdexLocationFromImageLocation(output_image_filename))
+      && VerifySymlink(ImageHeader::GetOatLocationFromImageLocation(input_image_filename),
+                       ImageHeader::GetOatLocationFromImageLocation(output_image_filename));
+}
+
+bool PatchOat::CreateVdexAndOatSymlinks(const std::string& input_image_filename,
+                                        const std::string& output_image_filename) {
+  std::string input_vdex_filename =
+      ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
+  std::string input_oat_filename =
+      ImageHeader::GetOatLocationFromImageLocation(input_image_filename);
+
+  std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str()));
+  if (input_oat_file.get() == nullptr) {
+    LOG(ERROR) << "Unable to open input oat file at " << input_oat_filename;
+    return false;
+  }
+  std::string error_msg;
+  std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat_file.get(),
+                                             PROT_READ | PROT_WRITE,
+                                             MAP_PRIVATE,
+                                             &error_msg));
+  if (elf.get() == nullptr) {
+    LOG(ERROR) << "Unable to open oat file " << input_oat_filename << " : " << error_msg;
+    return false;
+  }
+
+  MaybePic is_oat_pic = IsOatPic(elf.get());
+  if (is_oat_pic >= ERROR_FIRST) {
+    // Error logged by IsOatPic
+    return false;
+  } else if (is_oat_pic == NOT_PIC) {
+    LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_filename;
+    return false;
+  }
+
+  CHECK(is_oat_pic == PIC);
+
+  std::string output_vdex_filename =
+      ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
+  std::string output_oat_filename =
+      ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
+
+  return SymlinkFile(input_oat_filename, output_oat_filename) &&
+         SymlinkFile(input_vdex_filename, output_vdex_filename);
+}
+
 bool PatchOat::Patch(const std::string& image_location,
                      off_t delta,
                      const std::string& output_image_directory,
@@ -401,13 +460,11 @@
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   ScopedObjectAccess soa(Thread::Current());
 
-  t.NewTiming("Image Patching setup");
   std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
-  std::map<gc::space::ImageSpace*, std::unique_ptr<File>> space_to_file_map;
   std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>> space_to_memmap_map;
-  std::map<gc::space::ImageSpace*, PatchOat> space_to_patchoat_map;
 
   for (size_t i = 0; i < spaces.size(); ++i) {
+    t.NewTiming("Image Patching setup");
     gc::space::ImageSpace* space = spaces[i];
     std::string input_image_filename = space->GetImageFilename();
     std::unique_ptr<File> input_image(OS::OpenFileForReading(input_image_filename.c_str()));
@@ -445,139 +502,76 @@
       LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg;
       return false;
     }
-    space_to_file_map.emplace(space, std::move(input_image));
+
+
     space_to_memmap_map.emplace(space, std::move(image));
-  }
-
-  // Symlink PIC oat and vdex files and patch the image spaces in memory.
-  for (size_t i = 0; i < spaces.size(); ++i) {
-    gc::space::ImageSpace* space = spaces[i];
-    std::string input_image_filename = space->GetImageFilename();
-    std::string input_vdex_filename =
-        ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
-    std::string input_oat_filename =
-        ImageHeader::GetOatLocationFromImageLocation(input_image_filename);
-    std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str()));
-    if (input_oat_file.get() == nullptr) {
-      LOG(ERROR) << "Unable to open input oat file at " << input_oat_filename;
-      return false;
-    }
-    std::string error_msg;
-    std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat_file.get(),
-                                               PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg));
-    if (elf.get() == nullptr) {
-      LOG(ERROR) << "Unable to open oat file " << input_oat_file->GetPath() << " : " << error_msg;
-      return false;
-    }
-
-    if (output_image) {
-      MaybePic is_oat_pic = IsOatPic(elf.get());
-      if (is_oat_pic >= ERROR_FIRST) {
-        // Error logged by IsOatPic
-        return false;
-      } else if (is_oat_pic == NOT_PIC) {
-        LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_file->GetPath();
-        return false;
-      } else {
-        CHECK(is_oat_pic == PIC);
-
-        // Create a symlink.
-        std::string converted_image_filename = space->GetImageLocation();
-        std::replace(
-            converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
-        std::string output_image_filename = output_image_directory +
-            (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") +
-            converted_image_filename;
-        std::string output_vdex_filename =
-            ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
-        std::string output_oat_filename =
-            ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
-
-        if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(),
-                                       output_oat_filename) ||
-            !SymlinkFile(input_vdex_filename, output_vdex_filename)) {
-          // Errors already logged by above call.
-          return false;
-        }
-      }
-    }
-
-    PatchOat& p = space_to_patchoat_map.emplace(space,
-                                                PatchOat(
-                                                    isa,
-                                                    space_to_memmap_map.find(space)->second.get(),
-                                                    space->GetLiveBitmap(),
-                                                    space->GetMemMap(),
-                                                    delta,
-                                                    &space_to_memmap_map,
-                                                    timings)).first->second;
+    PatchOat p = PatchOat(isa,
+                          space_to_memmap_map.at(space).get(),
+                          space->GetLiveBitmap(),
+                          space->GetMemMap(),
+                          delta,
+                          &space_to_memmap_map,
+                          timings);
 
     t.NewTiming("Patching image");
     if (!p.PatchImage(i == 0)) {
       LOG(ERROR) << "Failed to patch image file " << input_image_filename;
       return false;
     }
-  }
 
-  if (output_image) {
     // Write the patched image spaces.
-    for (size_t i = 0; i < spaces.size(); ++i) {
-      gc::space::ImageSpace* space = spaces[i];
+    if (output_image) {
+      std::string output_image_filename;
+      if (!GetDalvikCacheFilename(space->GetImageLocation().c_str(),
+                                  output_image_directory.c_str(),
+                                  &output_image_filename,
+                                  &error_msg)) {
+        LOG(ERROR) << "Failed to find relocated image file name: " << error_msg;
+        return false;
+      }
+
+      if (!CreateVdexAndOatSymlinks(input_image_filename, output_image_filename))
+        return false;
 
       t.NewTiming("Writing image");
-      std::string converted_image_filename = space->GetImageLocation();
-      std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
-      std::string output_image_filename = output_image_directory +
-          (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") +
-          converted_image_filename;
       std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str()));
       if (output_image_file.get() == nullptr) {
         LOG(ERROR) << "Failed to open output image file at " << output_image_filename;
         return false;
       }
 
-      PatchOat& p = space_to_patchoat_map.find(space)->second;
-
       bool success = p.WriteImage(output_image_file.get());
       success = FinishFile(output_image_file.get(), success);
       if (!success) {
         return false;
       }
     }
-  }
 
-  if (output_image_relocation) {
-    // Write the image relocation information for each space.
-    for (size_t i = 0; i < spaces.size(); ++i) {
-      gc::space::ImageSpace* space = spaces[i];
-
+    if (output_image_relocation) {
       t.NewTiming("Writing image relocation");
       std::string original_image_filename(space->GetImageLocation() + ".rel");
       std::string image_relocation_filename =
           output_image_relocation_directory
               + (android::base::StartsWith(original_image_filename, "/") ? "" : "/")
               + original_image_filename.substr(original_image_filename.find_last_of("/"));
-      File& input_image = *space_to_file_map.find(space)->second;
-      int64_t input_image_size = input_image.GetLength();
+      int64_t input_image_size = input_image->GetLength();
       if (input_image_size < 0) {
         LOG(ERROR) << "Error while getting input image size";
         return false;
       }
-      std::string error_msg;
       std::unique_ptr<MemMap> original(MemMap::MapFile(input_image_size,
                                                        PROT_READ,
                                                        MAP_PRIVATE,
-                                                       input_image.Fd(),
+                                                       input_image->Fd(),
                                                        0,
                                                        /*low_4gb*/false,
-                                                       input_image.GetPath().c_str(),
+                                                       input_image->GetPath().c_str(),
                                                        &error_msg));
       if (original.get() == nullptr) {
-        LOG(ERROR) << "Unable to map image file " << input_image.GetPath() << " : " << error_msg;
+        LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg;
         return false;
       }
 
-      PatchOat& p = space_to_patchoat_map.find(space)->second;
       const MemMap* relocated = p.image_;
 
       if (!WriteRelFile(*original, *relocated, image_relocation_filename, &error_msg)) {
@@ -643,11 +637,10 @@
   std::string image_location_dir = android::base::Dirname(image_location);
   for (size_t i = 0; i < spaces.size(); ++i) {
     gc::space::ImageSpace* space = spaces[i];
-    std::string image_filename = space->GetImageLocation();
 
     std::string relocated_image_filename;
     std::string error_msg;
-    if (!GetDalvikCacheFilename(image_filename.c_str(),
+    if (!GetDalvikCacheFilename(space->GetImageLocation().c_str(),
             output_image_directory.c_str(), &relocated_image_filename, &error_msg)) {
       LOG(ERROR) << "Failed to find relocated image file name: " << error_msg;
       success = false;
@@ -658,7 +651,8 @@
     // basename:     boot.art
     // original:     /system/framework/arm64/boot.art
     // relocation:   /system/framework/arm64/boot.art.rel
-    std::string original_image_filename = GetSystemImageFilename(image_filename.c_str(), isa);
+    std::string original_image_filename =
+        GetSystemImageFilename(space->GetImageLocation().c_str(), isa);
 
     if (!CheckImageIdenticalToOriginalExceptForRelocation(
             relocated_image_filename, original_image_filename, &error_msg)) {
@@ -666,6 +660,13 @@
       success = false;
       break;
     }
+
+    if (!VerifyVdexAndOatSymlinks(original_image_filename, relocated_image_filename)) {
+      LOG(ERROR) << "Verification of vdex and oat symlinks for "
+                 << space->GetImageLocation() << " failed.";
+      success = false;
+      break;
+    }
   }
 
   if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
@@ -740,26 +741,6 @@
   return is_pic ? PIC : NOT_PIC;
 }
 
-bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
-                                         const std::string& output_oat_filename) {
-  // Delete the original file, since we won't need it.
-  unlink(output_oat_filename.c_str());
-
-  // Create a symlink from the old oat to the new oat
-  if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) {
-    int err = errno;
-    LOG(ERROR) << "Failed to create symlink at " << output_oat_filename
-               << " error(" << err << "): " << strerror(err);
-    return false;
-  }
-
-  if (kIsDebugBuild) {
-    LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename;
-  }
-
-  return true;
-}
-
 class PatchOat::PatchOatArtFieldVisitor : public ArtFieldVisitor {
  public:
   explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index ba59d57..feba523 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -91,10 +91,9 @@
   // Was the .oat image at oat_in made with --compile-pic ?
   static MaybePic IsOatPic(const ElfFile* oat_in);
 
-  // Attempt to replace the file with a symlink
-  // Returns false if it fails
-  static bool ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
-                                        const std::string& output_oat_filename);
+  static bool CreateVdexAndOatSymlinks(const std::string& input_image_filename,
+                                       const std::string& output_image_filename);
+
 
   void VisitObject(mirror::Object* obj)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/profman/Android.bp b/profman/Android.bp
index 6592b9d..163be2b 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -31,7 +31,6 @@
     },
 
     shared_libs: [
-        "libdexfile",
         "libbase",
     ],
 }
@@ -41,6 +40,7 @@
     defaults: ["profman-defaults"],
     shared_libs: [
         "libart",
+        "libdexfile",
     ],
 }
 
@@ -52,6 +52,7 @@
     ],
     shared_libs: [
         "libartd",
+        "libdexfiled",
     ],
 }
 
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 110b04f..1ac770f 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -409,7 +409,6 @@
         "jni_platform_headers",
     ],
     shared_libs: [
-        "libdexfile",
         "libnativebridge",
         "libnativeloader",
         "libbacktrace",
@@ -430,10 +429,7 @@
     // ART's macros.h depends on libbase's macros.h.
     // Note: runtime_options.h depends on cmdline. But we don't really want to export this
     //       generically. dex2oat takes care of it itself.
-    export_shared_lib_headers: [
-        "libbase",
-        "libdexfile",
-    ],
+    export_shared_lib_headers: ["libbase"],
 }
 
 gensrcs {
@@ -490,6 +486,8 @@
     strip: {
         keep_symbols: true,
     },
+    shared_libs: ["libdexfile"],
+    export_shared_lib_headers: ["libdexfile"],
 }
 
 art_cc_library {
@@ -498,6 +496,8 @@
         "art_debug_defaults",
         "libart_defaults",
     ],
+    shared_libs: ["libdexfiled"],
+    export_shared_lib_headers: ["libdexfiled"],
 }
 
 art_cc_library {
diff --git a/runtime/base/stringpiece.cc b/runtime/base/stringpiece.cc
index 672431c..aea4e74 100644
--- a/runtime/base/stringpiece.cc
+++ b/runtime/base/stringpiece.cc
@@ -23,13 +23,6 @@
 
 namespace art {
 
-#if !defined(NDEBUG)
-char StringPiece::operator[](size_type i) const {
-  CHECK_LT(i, length_);
-  return ptr_[i];
-}
-#endif
-
 void StringPiece::CopyToString(std::string* target) const {
   target->assign(ptr_, length_);
 }
diff --git a/runtime/base/stringpiece.h b/runtime/base/stringpiece.h
index 46743e9..e7109dc 100644
--- a/runtime/base/stringpiece.h
+++ b/runtime/base/stringpiece.h
@@ -20,6 +20,8 @@
 #include <string.h>
 #include <string>
 
+#include <android-base/logging.h>
+
 namespace art {
 
 // A string-like object that points to a sized piece of memory.
@@ -84,13 +86,10 @@
     length_ = len;
   }
 
-#if defined(NDEBUG)
   char operator[](size_type i) const {
+    DCHECK_LT(i, length_);
     return ptr_[i];
   }
-#else
-  char operator[](size_type i) const;
-#endif
 
   void remove_prefix(size_type n) {
     ptr_ += n;
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 5549122..05f099f 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -46,6 +46,7 @@
 #include "well_known_classes.h"
 
 namespace art {
+namespace {
 
 using android::base::StringAppendF;
 using android::base::StringPrintf;
@@ -1211,7 +1212,7 @@
     // this particular instance of JNIEnv.
     if (env != threadEnv) {
       // Get the thread owning the JNIEnv that's being used.
-      Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->self_;
+      Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->GetSelf();
       AbortF("thread %s using JNIEnv* from thread %s",
              ToStr<Thread>(*self).c_str(), ToStr<Thread>(*envThread).c_str());
       return false;
@@ -1223,7 +1224,7 @@
     case kFlag_CritOkay:    // okay to call this method
       break;
     case kFlag_CritBad:     // not okay to call
-      if (threadEnv->critical_ > 0) {
+      if (threadEnv->GetCritical() > 0) {
         AbortF("thread %s using JNI after critical get",
                ToStr<Thread>(*self).c_str());
         return false;
@@ -1231,25 +1232,25 @@
       break;
     case kFlag_CritGet:     // this is a "get" call
       // Don't check here; we allow nested gets.
-      if (threadEnv->critical_ == 0) {
-        threadEnv->critical_start_us_ = self->GetCpuMicroTime();
+      if (threadEnv->GetCritical() == 0) {
+        threadEnv->SetCriticalStartUs(self->GetCpuMicroTime());
       }
-      threadEnv->critical_++;
+      threadEnv->SetCritical(threadEnv->GetCritical() + 1);
       break;
     case kFlag_CritRelease:  // this is a "release" call
-      if (threadEnv->critical_ == 0) {
+      if (threadEnv->GetCritical() == 0) {
         AbortF("thread %s called too many critical releases",
                ToStr<Thread>(*self).c_str());
         return false;
-      } else if (threadEnv->critical_ == 1) {
+      } else if (threadEnv->GetCritical() == 1) {
         // Leaving the critical region, possibly warn about long critical regions.
-        uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->critical_start_us_;
+        uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->GetCriticalStartUs();
         if (critical_duration_us > kCriticalWarnTimeUs) {
           LOG(WARNING) << "JNI critical lock held for "
                        << PrettyDuration(UsToNs(critical_duration_us)) << " on " << *self;
         }
       }
-      threadEnv->critical_--;
+      threadEnv->SetCritical(threadEnv->GetCritical() - 1);
       break;
     default:
       LOG(FATAL) << "Bad flags (internal error): " << flags_;
@@ -2621,7 +2622,7 @@
   }
 
   static const JNINativeInterface* baseEnv(JNIEnv* env) {
-    return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions_;
+    return reinterpret_cast<JNIEnvExt*>(env)->GetUncheckedFunctions();
   }
 
   static jobject NewRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
@@ -3847,10 +3848,6 @@
   CheckJNI::GetObjectRefType,
 };
 
-const JNINativeInterface* GetCheckJniNativeInterface() {
-  return &gCheckNativeInterface;
-}
-
 class CheckJII {
  public:
   static jint DestroyJavaVM(JavaVM* vm) {
@@ -3922,6 +3919,12 @@
   CheckJII::AttachCurrentThreadAsDaemon
 };
 
+}  // anonymous namespace
+
+const JNINativeInterface* GetCheckJniNativeInterface() {
+  return &gCheckNativeInterface;
+}
+
 const JNIInvokeInterface* GetCheckJniInvokeInterface() {
   return &gCheckInvokeInterface;
 }
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index cd6e8d5..ae06f8f 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -226,14 +226,7 @@
     const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
     if (klass != nullptr) {
-      if (klass->IsInterface()) {
-        resolved = klass->FindInterfaceMethod(dex_cache, method_idx, pointer_size);
-      } else {
-        resolved = klass->FindClassMethod(dex_cache, method_idx, pointer_size);
-      }
-      if (resolved != nullptr) {
-        dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size);
-      }
+      resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
     }
   }
   return resolved;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c4b1bf8..63d47e6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7939,6 +7939,39 @@
   return oss.str();
 }
 
+ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
+                                           ObjPtr<mirror::DexCache> dex_cache,
+                                           ObjPtr<mirror::ClassLoader> class_loader,
+                                           uint32_t method_idx) {
+  // Search for the method using dex_cache and method_idx. The Class::Find*Method()
+  // functions can optimize the search if the dex_cache is the same as the DexCache
+  // of the class, with fall-back to name and signature search otherwise.
+  ArtMethod* resolved = nullptr;
+  if (klass->IsInterface()) {
+    resolved = klass->FindInterfaceMethod(dex_cache, method_idx, image_pointer_size_);
+  } else {
+    resolved = klass->FindClassMethod(dex_cache, method_idx, image_pointer_size_);
+  }
+  DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
+  if (resolved != nullptr) {
+    // In case of jmvti, the dex file gets verified before being registered, so first
+    // check if it's registered before checking class tables.
+    const DexFile& dex_file = *dex_cache->GetDexFile();
+    CHECK(!IsDexFileRegistered(Thread::Current(), dex_file) ||
+          FindClassTable(Thread::Current(), dex_cache) == ClassTableForClassLoader(class_loader))
+        << "DexFile referrer: " << dex_file.GetLocation()
+        << " ClassLoader: " << DescribeLoaders(class_loader, "");
+    // Be a good citizen and update the dex cache to speed subsequent calls.
+    dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_);
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+    DCHECK(LookupResolvedType(method_id.class_idx_, dex_cache, class_loader) != nullptr)
+        << "Method: " << resolved->PrettyMethod() << ", "
+        << "Class: " << klass->PrettyClass() << " (" << klass->GetStatus() << "), "
+        << "DexFile referrer: " << dex_file.GetLocation();
+  }
+  return resolved;
+}
+
 template <ClassLinker::ResolveMode kResolveMode>
 ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
                                       Handle<mirror::DexCache> dex_cache,
@@ -7971,6 +8004,7 @@
           << resolved->PrettyMethod() << ";" << resolved
           << "/0x" << std::hex << resolved->GetAccessFlags()
           << " ReferencedClass: " << descriptor
+          << " DexFile referrer: " << dex_file.GetLocation()
           << " ClassLoader: " << DescribeLoaders(class_loader.Get(), descriptor);
     }
   } else {
@@ -7991,19 +8025,7 @@
   }
 
   if (!valid_dex_cache_method) {
-    // Search for the method using dex_cache and method_idx. The Class::Find*Method()
-    // functions can optimize the search if the dex_cache is the same as the DexCache
-    // of the class, with fall-back to name and signature search otherwise.
-    if (klass->IsInterface()) {
-      resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, pointer_size);
-    } else {
-      resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, pointer_size);
-    }
-    DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
-    if (resolved != nullptr) {
-      // Be a good citizen and update the dex cache to speed subsequent calls.
-      dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size);
-    }
+    resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
   }
 
   // Note: We can check for IllegalAccessError only if we have a referrer.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 16fa1ce..712e3ae 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,9 +27,9 @@
 #include "base/enums.h"
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "dex/dex_cache_resolved_classes.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_types.h"
-#include "dex_cache_resolved_classes.h"
 #include "gc_root.h"
 #include "handle.h"
 #include "jni.h"
@@ -312,6 +312,13 @@
                                   ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Find a method with the given index from class `klass`, and update the dex cache.
+  ArtMethod* FindResolvedMethod(ObjPtr<mirror::Class> klass,
+                                ObjPtr<mirror::DexCache> dex_cache,
+                                ObjPtr<mirror::ClassLoader> class_loader,
+                                uint32_t method_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Resolve a method with a given ID from the DexFile associated with the given DexCache
   // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are
   // used as in ResolveType. What is unique is the method type argument which is used to
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 9ef7d42..404c535 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -99,14 +99,13 @@
                << "This must be due to playing wrongly with class loaders";
   }
 
-  inlined_method = klass->FindClassMethod(dex_cache, method_index, kRuntimePointerSize);
+  inlined_method = class_linker->FindResolvedMethod(klass, dex_cache, class_loader, method_index);
   if (inlined_method == nullptr) {
     LOG(FATAL) << "Could not find an inlined method from an .oat file: the class " << descriptor
                << " does not have " << dex_file->GetMethodName(method_id)
                << dex_file->GetMethodSignature(method_id) << " declared. "
                << "This must be due to duplicate classes or playing wrongly with class loaders";
   }
-  dex_cache->SetResolvedMethod(method_index, inlined_method, kRuntimePointerSize);
 
   return inlined_method;
 }
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index 6cd9dc1..795faa8 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -38,6 +38,7 @@
 
 class ArtMethod;
 template<class MirrorType> class GcRoot;
+template<class MirrorType> class StackReference;
 class Thread;
 
 // Pointers to functions that are called by quick compiler generated code via thread-local storage.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index a8c328f..344e5be 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -649,10 +649,6 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   return QuickArgumentVisitor::GetProxyThisObjectReference(sp)->AsMirrorPtr();
 }
-extern "C" StackReference<mirror::Object>* artQuickGetProxyThisObjectReference(ArtMethod** sp)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return QuickArgumentVisitor::GetProxyThisObjectReference(sp);
-}
 
 // Visits arguments on the stack placing them into the shadow frame.
 class BuildQuickShadowFrameVisitor FINAL : public QuickArgumentVisitor {
@@ -953,7 +949,8 @@
   std::vector<jvalue> args;
   uint32_t shorty_len = 0;
   const char* shorty = non_proxy_method->GetShorty(&shorty_len);
-  BuildQuickArgumentVisitor local_ref_visitor(sp, false, shorty, shorty_len, &soa, &args);
+  BuildQuickArgumentVisitor local_ref_visitor(
+      sp, /* is_static */ false, shorty, shorty_len, &soa, &args);
 
   local_ref_visitor.VisitArguments();
   DCHECK_GT(args.size(), 0U) << proxy_method->PrettyMethod();
@@ -982,6 +979,106 @@
   return result.GetJ();
 }
 
+// Visitor returning a reference argument at a given position in a Quick stack frame.
+// NOTE: Only used for testing purposes.
+class GetQuickReferenceArgumentAtVisitor FINAL : public QuickArgumentVisitor {
+ public:
+  GetQuickReferenceArgumentAtVisitor(ArtMethod** sp,
+                                     const char* shorty,
+                                     uint32_t shorty_len,
+                                     size_t arg_pos)
+      : QuickArgumentVisitor(sp, /* is_static */ false, shorty, shorty_len),
+        cur_pos_(0u),
+        arg_pos_(arg_pos),
+        ref_arg_(nullptr) {
+          CHECK_LT(arg_pos, shorty_len) << "Argument position greater than the number arguments";
+        }
+
+  void Visit() REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE {
+    if (cur_pos_ == arg_pos_) {
+      Primitive::Type type = GetParamPrimitiveType();
+      CHECK_EQ(type, Primitive::kPrimNot) << "Argument at searched position is not a reference";
+      ref_arg_ = reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+    }
+    ++cur_pos_;
+  }
+
+  StackReference<mirror::Object>* GetReferenceArgument() {
+    return ref_arg_;
+  }
+
+ private:
+  // The position of the currently visited argument.
+  size_t cur_pos_;
+  // The position of the searched argument.
+  const size_t arg_pos_;
+  // The reference argument, if found.
+  StackReference<mirror::Object>* ref_arg_;
+
+  DISALLOW_COPY_AND_ASSIGN(GetQuickReferenceArgumentAtVisitor);
+};
+
+// Returning reference argument at position `arg_pos` in Quick stack frame at address `sp`.
+// NOTE: Only used for testing purposes.
+extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt(size_t arg_pos,
+                                                                               ArtMethod** sp)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ArtMethod* proxy_method = *sp;
+  ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+  CHECK(!non_proxy_method->IsStatic())
+      << proxy_method->PrettyMethod() << " " << non_proxy_method->PrettyMethod();
+  uint32_t shorty_len = 0;
+  const char* shorty = non_proxy_method->GetShorty(&shorty_len);
+  GetQuickReferenceArgumentAtVisitor ref_arg_visitor(sp, shorty, shorty_len, arg_pos);
+  ref_arg_visitor.VisitArguments();
+  StackReference<mirror::Object>* ref_arg = ref_arg_visitor.GetReferenceArgument();
+  return ref_arg;
+}
+
+// Visitor returning all the reference arguments in a Quick stack frame.
+class GetQuickReferenceArgumentsVisitor FINAL : public QuickArgumentVisitor {
+ public:
+  GetQuickReferenceArgumentsVisitor(ArtMethod** sp,
+                                    bool is_static,
+                                    const char* shorty,
+                                    uint32_t shorty_len)
+      : QuickArgumentVisitor(sp, is_static, shorty, shorty_len) {}
+
+  void Visit() REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE {
+    Primitive::Type type = GetParamPrimitiveType();
+    if (type == Primitive::kPrimNot) {
+      StackReference<mirror::Object>* ref_arg =
+          reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+      ref_args_.push_back(ref_arg);
+    }
+  }
+
+  std::vector<StackReference<mirror::Object>*> GetReferenceArguments() {
+    return ref_args_;
+  }
+
+ private:
+  // The reference arguments.
+  std::vector<StackReference<mirror::Object>*> ref_args_;
+
+  DISALLOW_COPY_AND_ASSIGN(GetQuickReferenceArgumentsVisitor);
+};
+
+// Returning all reference arguments in Quick stack frame at address `sp`.
+std::vector<StackReference<mirror::Object>*> GetProxyReferenceArguments(ArtMethod** sp)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ArtMethod* proxy_method = *sp;
+  ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+  CHECK(!non_proxy_method->IsStatic())
+      << proxy_method->PrettyMethod() << " " << non_proxy_method->PrettyMethod();
+  uint32_t shorty_len = 0;
+  const char* shorty = non_proxy_method->GetShorty(&shorty_len);
+  GetQuickReferenceArgumentsVisitor ref_args_visitor(sp, /* is_static */ false, shorty, shorty_len);
+  ref_args_visitor.VisitArguments();
+  std::vector<StackReference<mirror::Object>*> ref_args = ref_args_visitor.GetReferenceArguments();
+  return ref_args;
+}
+
 // Read object references held in arguments from quick frames and place in a JNI local references,
 // so they don't get garbage collected.
 class RememberForGcArgumentVisitor FINAL : public QuickArgumentVisitor {
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 24cedb0..0ae6dbf 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -269,7 +269,20 @@
         }
       } else {
         CHECK_NE(return_pc, 0U);
-        CHECK(!reached_existing_instrumentation_frames_);
+        if (UNLIKELY(reached_existing_instrumentation_frames_)) {
+          std::string thread_name;
+          GetThread()->GetThreadName(thread_name);
+          uint32_t dex_pc = dex::kDexNoIndex;
+          if (last_return_pc_ != 0 &&
+              GetCurrentOatQuickMethodHeader() != nullptr) {
+            dex_pc = GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_);
+          }
+          LOG(FATAL) << "While walking " << thread_name << " found existing instrumentation frames."
+                     << " method is " << GetMethod()->PrettyMethod()
+                     << " return_pc is " << std::hex << return_pc
+                     << " dex pc: " << dex_pc;
+          UNREACHABLE();
+        }
         InstrumentationStackFrame instrumentation_frame(
             m->IsRuntimeMethod() ? nullptr : GetThisObject(),
             m,
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 8c81c25..ac20afe 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -225,7 +225,7 @@
 
   // Extra checking.
   bool check_jni_;
-  bool force_copy_;
+  const bool force_copy_;
   const bool tracing_enabled_;
 
   // Extra diagnostics.
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index dcb4a20..21caa42 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -1195,22 +1195,10 @@
       return kProfileLoadBadData;
     }
 
-    std::unique_ptr<MemMap> map;
-    if (zip_entry->IsUncompressed()) {
-      // Map uncompressed files within zip as file-backed to avoid a dirty copy.
-      map.reset(zip_entry->MapDirectlyFromFile(kDexMetadataProfileEntry, error));
-      if (map == nullptr) {
-        LOG(WARNING) << "Can't mmap profile directly; "
-                     << "is your ZIP file corrupted? Falling back to extraction.";
-        // Try again with Extraction which still has a chance of recovery.
-      }
-    }
-
-    if (map == nullptr) {
-      // Default path for compressed ZIP entries, and fallback for stored ZIP entries.
-      // TODO(calin) pass along file names to assist with debugging.
-      map.reset(zip_entry->ExtractToMemMap("profile file", kDexMetadataProfileEntry, error));
-    }
+    // TODO(calin) pass along file names to assist with debugging.
+    std::unique_ptr<MemMap> map(zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry,
+                                                                "profile file",
+                                                                error));
 
     if (map != nullptr) {
       source->reset(ProfileSource::Create(std::move(map)));
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 5488a9e..3213c85 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -24,7 +24,7 @@
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "bit_memory_region.h"
-#include "dex_cache_resolved_classes.h"
+#include "dex/dex_cache_resolved_classes.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_types.h"
 #include "method_reference.h"
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 0e8fd03..291ac48 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -96,6 +96,15 @@
   }
 
   Thread* GetSelf() const { return self_; }
+  uint32_t GetCritical() const { return critical_; }
+  void SetCritical(uint32_t new_critical) { critical_ = new_critical; }
+  uint64_t GetCriticalStartUs() const { return critical_start_us_; }
+  void SetCriticalStartUs(uint64_t new_critical_start_us) {
+    critical_start_us_ = new_critical_start_us;
+  }
+  const JNINativeInterface* GetUncheckedFunctions() const {
+    return unchecked_functions_;
+  }
   JavaVMExt* GetVm() const { return vm_; }
 
   bool IsRuntimeDeleted() const { return runtime_deleted_; }
@@ -190,9 +199,7 @@
   // If we are a JNI env for a daemon thread with a deleted runtime.
   bool runtime_deleted_;
 
-  friend class CheckJNI;
   friend class JNI;
-  friend class ScopedCheck;
   friend class ScopedJniEnvLocalRefState;
   friend class Thread;
   ART_FRIEND_TEST(JniInternalTest, JNIEnvExtOffsets);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 57a429c..505b745 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -405,18 +405,15 @@
   }
   const DexFile* dex_file = dex_cache->GetDexFile();
   const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
-  ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  ObjPtr<mirror::Class> klass = class_linker->LookupResolvedType(
       method_id.class_idx_, dex_cache, /* class_loader */ nullptr);
   if (klass == nullptr) {
     return;
   }
-  ArtMethod* method = klass->IsInterface()
-      ? klass->FindInterfaceMethod(dex_cache, method_idx, kRuntimePointerSize)
-      : klass->FindClassMethod(dex_cache, method_idx, kRuntimePointerSize);
-  if (method == nullptr) {
-    return;
-  }
-  dex_cache->SetResolvedMethod(method_idx, method, kRuntimePointerSize);
+  // Call FindResolvedMethod to populate the dex cache.
+  class_linker->FindResolvedMethod(klass, dex_cache, /* class_loader */ nullptr, method_idx);
 }
 
 struct DexCacheStats {
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 12400e2..08e471b 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -277,7 +277,10 @@
                                             jlong token,
                                             jint runtime_flags,
                                             jboolean is_system_server,
+                                            jboolean is_zygote,
                                             jstring instruction_set) {
+  DCHECK(!(is_system_server && is_zygote));
+
   Thread* thread = reinterpret_cast<Thread*>(token);
   // Our system thread ID, etc, has changed so reset Thread state.
   thread->InitAfterFork();
@@ -346,13 +349,22 @@
     }
   }
 
-  DCHECK(!is_system_server || !do_hidden_api_checks)
-      << "SystemServer should be forked with DISABLE_HIDDEN_API_CHECKS";
+  DCHECK(!(is_system_server && do_hidden_api_checks))
+      << "SystemServer should be forked with ENABLE_HIDDEN_API_CHECKS";
+  DCHECK(!(is_zygote && do_hidden_api_checks))
+      << "Child zygote processes should be forked with ENABLE_HIDDEN_API_CHECKS";
   Runtime::Current()->SetHiddenApiChecksEnabled(do_hidden_api_checks);
 
   // Clear the hidden API warning flag, in case it was set.
   Runtime::Current()->SetPendingHiddenApiWarning(false);
 
+  if (is_zygote) {
+    // If creating a child-zygote, do not call into the runtime's post-fork logic.
+    // Doing so would spin up threads for Binder and JDWP. Instead, the Java side
+    // of the child process will call a static main in a class specified by the parent.
+    return;
+  }
+
   if (instruction_set != nullptr && !is_system_server) {
     ScopedUtfChars isa_string(env, instruction_set);
     InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
@@ -380,7 +392,7 @@
 
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
-  NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZLjava/lang/String;)V"),
+  NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZZLjava/lang/String;)V"),
   NATIVE_METHOD(ZygoteHooks, startZygoteNoThreadCreation, "()V"),
   NATIVE_METHOD(ZygoteHooks, stopZygoteNoThreadCreation, "()V"),
 };
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 2ee7f9d..1de7b20 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3436,7 +3436,7 @@
   return object != nullptr && object->GetLockOwnerThreadId() == GetThreadId();
 }
 
-extern "C" StackReference<mirror::Object>* artQuickGetProxyThisObjectReference(ArtMethod** sp)
+extern std::vector<StackReference<mirror::Object>*> GetProxyReferenceArguments(ArtMethod** sp)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // RootVisitor parameters are: (const Object* obj, size_t vreg, const StackVisitor* visitor).
@@ -3482,7 +3482,7 @@
       }
     }
     // Mark lock count map required for structured locking checks.
-    shadow_frame->GetLockCountData().VisitMonitors(visitor_, -1, this);
+    shadow_frame->GetLockCountData().VisitMonitors(visitor_, /* vreg */ -1, this);
   }
 
  private:
@@ -3520,7 +3520,7 @@
         }
       }
       mirror::Object* new_ref = klass.Ptr();
-      visitor_(&new_ref, -1, this);
+      visitor_(&new_ref, /* vreg */ -1, this);
       if (new_ref != klass) {
         method->CASDeclaringClass(klass.Ptr(), new_ref->AsClass());
       }
@@ -3583,17 +3583,20 @@
           }
         }
       }
-    } else if (!m->IsStatic() && !m->IsRuntimeMethod() && m->IsProxyMethod()) {
-      // If this is a non-static proxy method, visit its target (`this` object).
+    } else if (!m->IsRuntimeMethod() && m->IsProxyMethod()) {
+      // If this is a proxy method, visit its reference arguments.
+      DCHECK(!m->IsStatic());
       DCHECK(!m->IsNative());
-      StackReference<mirror::Object>* ref_addr =
-          artQuickGetProxyThisObjectReference(cur_quick_frame);
-      mirror::Object* ref = ref_addr->AsMirrorPtr();
-      if (ref != nullptr) {
-        mirror::Object* new_ref = ref;
-        visitor_(&new_ref, -1, this);
-        if (ref != new_ref) {
-          ref_addr->Assign(new_ref);
+      std::vector<StackReference<mirror::Object>*> ref_addrs =
+          GetProxyReferenceArguments(cur_quick_frame);
+      for (StackReference<mirror::Object>* ref_addr : ref_addrs) {
+        mirror::Object* ref = ref_addr->AsMirrorPtr();
+        if (ref != nullptr) {
+          mirror::Object* new_ref = ref;
+          visitor_(&new_ref, /* vreg */ -1, this);
+          if (ref != new_ref) {
+            ref_addr->Assign(new_ref);
+          }
         }
       }
     }
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 0829c54..443c35f 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -263,18 +263,6 @@
   UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction);
 }
 
-static void UpdateAccessFlags(uint8_t* data, uint32_t new_flag, bool is_method) {
-  // Go back 1 uleb to start.
-  data = ReverseSearchUnsignedLeb128(data);
-  if (is_method) {
-    // Methods have another uleb field before the access flags
-    data = ReverseSearchUnsignedLeb128(data);
-  }
-  DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)),
-            new_flag);
-  UpdateUnsignedLeb128(data, new_flag);
-}
-
 void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
                                 const uint8_t* source_dex_begin,
                                 bool decompile_return_instruction) const {
@@ -312,14 +300,8 @@
                 quicken_data,
                 decompile_return_instruction);
           }
-          UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()),
-                            class_it.GetMemberAccessFlags(),
-                            /*is_method*/ true);
-        } else {
-          UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()),
-                            class_it.GetMemberAccessFlags(),
-                            /*is_method*/ false);
         }
+        DexFile::UnHideAccessFlags(class_it);
       }
     }
   }
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 3e9dfd1..66e578f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3899,21 +3899,13 @@
   }
   ObjPtr<mirror::Class> klass = klass_type.GetClass();
   const RegType& referrer = GetDeclaringClass();
-  auto* cl = Runtime::Current()->GetClassLinker();
-  auto pointer_size = cl->GetImagePointerSize();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  PointerSize pointer_size = class_linker->GetImagePointerSize();
 
   ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx, pointer_size);
   if (res_method == nullptr) {
-    // Try to find the method with the appropriate lookup for the klass type (interface or not).
-    // If this lookup does not match `method_type`, errors shall be reported below.
-    if (klass->IsInterface()) {
-      res_method = klass->FindInterfaceMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
-    } else {
-      res_method = klass->FindClassMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
-    }
-    if (res_method != nullptr) {
-      dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size);
-    }
+    res_method = class_linker->FindResolvedMethod(
+        klass, dex_cache_.Get(), class_loader_.Get(), dex_method_idx);
   }
 
   // Record result of method resolution attempt. The klass resolution has recorded whether
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index 2caed4b..5b3cab4 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -193,6 +193,19 @@
   return map.release();
 }
 
+MemMap* ZipEntry::MapDirectlyOrExtract(const char* zip_filename,
+                                       const char* entry_filename,
+                                       std::string* error_msg) {
+  if (IsUncompressed() && GetFileDescriptor(handle_) >= 0) {
+    MemMap* ret = MapDirectlyFromFile(zip_filename, error_msg);
+    if (ret != nullptr) {
+      return ret;
+    }
+  }
+  // Fall back to extraction for the failure case.
+  return ExtractToMemMap(zip_filename, entry_filename, error_msg);
+}
+
 static void SetCloseOnExec(int fd) {
   // This dance is more portable than Linux's O_CLOEXEC open(2) flag.
   int flags = fcntl(fd, F_GETFD);
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 70518e1..2ca4aa2 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -55,6 +55,10 @@
   MemMap* MapDirectlyFromFile(const char* zip_filename, /*out*/std::string* error_msg);
   virtual ~ZipEntry();
 
+  MemMap* MapDirectlyOrExtract(const char* zip_filename,
+                               const char* entry_filename,
+                               std::string* error_msg);
+
   uint32_t GetUncompressedLength();
   uint32_t GetCrc32();
 
diff --git a/test/1945-proxy-method-arguments/expected.txt b/test/1945-proxy-method-arguments/expected.txt
new file mode 100644
index 0000000..1824953
--- /dev/null
+++ b/test/1945-proxy-method-arguments/expected.txt
@@ -0,0 +1,26 @@
+JNI_OnLoad called
+proxy: $Proxy0
+Proxy for interface TestInterface.method0
+  arg0: $Proxy0
+Proxy for interface TestInterface.method1
+  arg0: $Proxy0
+  arg1: java.lang.String "a"
+Proxy for interface TestInterface.method10
+  arg0: $Proxy0
+  arg1: java.lang.String "one"
+  arg2: java.lang.String "two"
+  arg3: java.lang.String "three"
+  arg4: java.lang.String "four"
+  arg5: java.lang.String "five"
+  arg6: java.lang.String "six"
+  arg7: java.lang.String "seven"
+  arg8: java.lang.String "eight"
+  arg9: java.lang.String "nine"
+  arg10: java.lang.String "ten"
+Proxy for interface TestInterface.method10Even
+  arg0: $Proxy0
+  arg2: java.lang.String "two"
+  arg4: java.lang.String "four"
+  arg6: java.lang.String "six"
+  arg8: java.lang.String "eight"
+  arg10: java.lang.String "ten"
diff --git a/test/1945-proxy-method-arguments/get_args.cc b/test/1945-proxy-method-arguments/get_args.cc
new file mode 100644
index 0000000..211ae10
--- /dev/null
+++ b/test/1945-proxy-method-arguments/get_args.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "arch/context.h"
+#include "art_method-inl.h"
+#include "jni.h"
+#include "oat_quick_method_header.h"
+#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace {
+
+// Visit a proxy method Quick frame at a given depth.
+class GetProxyQuickFrameVisitor FINAL : public StackVisitor {
+ public:
+  GetProxyQuickFrameVisitor(art::Thread* target, art::Context* ctx, size_t frame_depth)
+      REQUIRES_SHARED(art::Locks::mutator_lock_)
+      : art::StackVisitor(target, ctx, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+        cur_depth_(0u),
+        frame_depth_(frame_depth),
+        quick_frame_(nullptr) {}
+
+  bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (GetMethod()->IsRuntimeMethod()) {
+      return true;
+    }
+    if (cur_depth_ == frame_depth_) {
+      // Found frame.
+      ShadowFrame* shadow_frame = GetCurrentShadowFrame();
+      if (shadow_frame != nullptr) {
+        // Nothing to do.
+      } else {
+        VisitQuickFrameAtSearchedDepth();
+      }
+      return false;
+    } else {
+      ++cur_depth_;
+      return true;
+    }
+  }
+
+  void VisitQuickFrameAtSearchedDepth() REQUIRES_SHARED(Locks::mutator_lock_) {
+    quick_frame_ = GetCurrentQuickFrame();
+    CHECK(quick_frame_ != nullptr);
+    ArtMethod* method = *quick_frame_;
+    CHECK(method != nullptr);
+    CHECK(method->IsProxyMethod()) << method->PrettyMethod();
+  }
+
+  // Return the found Quick frame.
+  ArtMethod** GetQuickFrame() {
+    return quick_frame_;
+  }
+
+ private:
+  // The depth of the currently visited frame.
+  size_t cur_depth_;
+  // The depth of the currently searched frame.
+  size_t frame_depth_;
+  // The quick frame, if found.
+  ArtMethod** quick_frame_;
+  // Method name
+
+  DISALLOW_COPY_AND_ASSIGN(GetProxyQuickFrameVisitor);
+};
+
+extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt(size_t arg_pos,
+                                                                               ArtMethod** sp)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+jobject GetProxyReferenceArgument(size_t arg_pos, size_t proxy_method_frame_depth) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+  std::unique_ptr<Context> context(Context::Create());
+
+  GetProxyQuickFrameVisitor visitor(self, context.get(), proxy_method_frame_depth);
+  visitor.WalkStack();
+  ArtMethod** quick_frame = visitor.GetQuickFrame();
+  CHECK(quick_frame != nullptr);
+
+  // Find reference argument in frame.
+  StackReference<mirror::Object>* ref_arg =
+      artQuickGetProxyReferenceArgumentAt(arg_pos, quick_frame);
+  CHECK(ref_arg != nullptr);
+  art::ObjPtr<mirror::Object> obj = ref_arg->AsMirrorPtr();
+
+  return obj.IsNull() ? nullptr : soa.AddLocalReference<jobject>(obj);
+}
+
+extern "C" JNIEXPORT jobject JNICALL Java_TestInvocationHandler_getArgument(
+    JNIEnv* env ATTRIBUTE_UNUSED, jobject thiz ATTRIBUTE_UNUSED, int arg_pos, int frame_depth) {
+  return GetProxyReferenceArgument(arg_pos, frame_depth);
+}
+
+}  // namespace
+
+}  // namespace art
diff --git a/test/1945-proxy-method-arguments/info.txt b/test/1945-proxy-method-arguments/info.txt
new file mode 100644
index 0000000..15ccc44
--- /dev/null
+++ b/test/1945-proxy-method-arguments/info.txt
@@ -0,0 +1,7 @@
+Test checking that reference arguments of proxy methods are visited as
+thread stack roots when visiting Quick frames roots (b/73149739).
+Previously, if the proxy method (direcly or indirectly) executed code
+accessing one of these reference arguments in the proxy method stack
+frame, it could end up with a stale reference, as the corresponding
+object may have been moved by the garbage collector, but the stack
+reference would not have been updated.
diff --git a/test/1945-proxy-method-arguments/src/Main.java b/test/1945-proxy-method-arguments/src/Main.java
new file mode 100644
index 0000000..b04a661
--- /dev/null
+++ b/test/1945-proxy-method-arguments/src/Main.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+interface TestInterface {
+  void method0();
+  void method1(String arg);
+  void method10(String arg1, String arg2, String arg3, String arg4, String arg5,
+                String arg6, String arg7, String arg8, String arg9, String arg10);
+  void method10Even(byte arg1, String arg2, short arg3, String arg4, int arg5,
+                    String arg6, long arg7, String arg8, double arg9, String arg10);
+}
+
+class TestInvocationHandler implements InvocationHandler {
+  @Override
+  public Object invoke(Object proxy, Method method, Object[] args) {
+    // Force garbage collection to try to make `proxy` move in memory
+    // (in the case of a moving garbage collector).
+    System.gc();
+
+    System.out.println("Proxy for " + TestInterface.class + "." + method.getName());
+    if (method.getName().equals("method0")) {
+      testMethod0(proxy, args);
+    } else if (method.getName().equals("method1")) {
+      testMethod1(proxy, args);
+    } else if (method.getName().equals("method10")) {
+      testMethod10(proxy, args);
+    } else if (method.getName().equals("method10Even")) {
+      testMethod10Even(proxy, args);
+    }
+    return null;
+  }
+
+  private void testMethod0(Object proxy, Object[] args) {
+    // Get argument 0 (method target) from the proxy method frame ($Proxy0.method0 activation).
+    Object arg0 = getProxyMethodArgument(0);
+    System.out.println("  arg0: " + arg0.getClass().getName());
+    Main.assertEquals(proxy, arg0);
+  }
+
+  private void testMethod1(Object proxy, Object[] args) {
+    // Get argument 0 (method target) from the proxy method frame ($Proxy0.method0 activation).
+    Object arg0 = getProxyMethodArgument(0);
+    System.out.println("  arg0: " + arg0.getClass().getName());
+    Main.assertEquals(proxy, arg0);
+    // Get argument 1 from the proxy method frame ($Proxy0.method1 activation).
+    String arg1 = (String) getProxyMethodArgument(1);
+    System.out.println("  arg1: " + arg1.getClass().getName() + " \"" + arg1 + "\"");
+    Main.assertEquals(args[0], arg1);
+  }
+
+  private void testMethod10(Object proxy, Object[] args) {
+    // Get argument 0 (method target) from the proxy method frame ($Proxy0.method10 activation).
+    Object arg0 = getProxyMethodArgument(0);
+    System.out.println("  arg0: " + arg0.getClass().getName());
+    Main.assertEquals(proxy, arg0);
+    // Get argument `i` from the proxy method frame ($Proxy0.method10 activation).
+    for (int i = 0; i < 10; ++i) {
+      int arg_pos = i + 1;
+      String arg = (String) getProxyMethodArgument(arg_pos);
+      System.out.println("  arg" + arg_pos + ": " + arg.getClass().getName() + " \"" + arg + "\"");
+      Main.assertEquals(args[i], arg);
+    }
+  }
+
+  private void testMethod10Even(Object proxy, Object[] args) {
+    // Get argument 0 (method target) from the proxy method frame ($Proxy0.method10Even
+    // activation).
+    Object arg0 = getProxyMethodArgument(0);
+    System.out.println("  arg0: " + arg0.getClass().getName());
+    Main.assertEquals(proxy, arg0);
+    // Get argument `i` from the proxy method frame ($Proxy0.method10Even activation).
+    for (int i = 1; i < 10; i += 2) {
+      int arg_pos = i + 1;
+      String arg = (String) getProxyMethodArgument(arg_pos);
+      System.out.println("  arg" + arg_pos + ": " + arg.getClass().getName() + " \"" + arg + "\"");
+      Main.assertEquals(args[i], arg);
+    }
+  }
+
+  // Get reference argument at position `arg_pos` in proxy frame.
+  // This method should only be called from one of the
+  // `TestInvocationHandler.testMethod*` methods via `TestInvocationHandler.invoke`.
+  private Object getProxyMethodArgument(int arg_pos) {
+    // Find proxy frame in stack (from a testMethod* method).
+    //
+    //     depth  method
+    //     ----------------------------------------------------------------------
+    //     0      TestInvocationHandler.getArgument             (outermost frame)
+    //     1      TestInvocationHandler.getProxyMethodArgument
+    //     2      TestInvocationHandler.testMethod*
+    //     3      TestInvocationHandler.invoke
+    //     4      java.lang.reflect.Proxy.invoke
+    //  -> 5      TestInterface.method*                         (proxy method)
+    //     6      Main.main                                     (innermost frame)
+    //
+    int proxy_method_frame_depth = 5;
+    return getArgument(arg_pos, proxy_method_frame_depth);
+  }
+
+  // Get reference argument at position `arg_pos` in frame at depth `frame_depth`.
+  private native Object getArgument(int arg_pos, int frame_depth);
+}
+
+public class Main {
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+
+    TestInvocationHandler invocationHandler = new TestInvocationHandler();
+    TestInterface proxy = (TestInterface) Proxy.newProxyInstance(
+        Main.class.getClassLoader(),
+        new Class<?>[] { TestInterface.class },
+        invocationHandler);
+    System.out.println("proxy: " + proxy.getClass().getName());
+
+    proxy.method0();
+    proxy.method1("a");
+    proxy.method10("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");
+    proxy.method10Even((byte) 1, "two", (short) 3, "four", 5, "six", 7L, "eight", 9.0, "ten");
+  }
+
+  public static void assertEquals(Object expected, Object actual) {
+    if (expected != actual) {
+      throw new Error("Expected " + expected  + ", got " + actual);
+    }
+  }
+
+  public static void assertEquals(String expected, String actual) {
+    if (expected != actual) {
+      throw new Error("Expected \"" + expected  + "\", got \"" + actual + "\"");
+    }
+  }
+}
diff --git a/test/990-method-handle-and-mr/build b/test/807-method-handle-and-mr/build
similarity index 100%
rename from test/990-method-handle-and-mr/build
rename to test/807-method-handle-and-mr/build
diff --git a/test/990-method-handle-and-mr/expected.txt b/test/807-method-handle-and-mr/expected.txt
similarity index 100%
rename from test/990-method-handle-and-mr/expected.txt
rename to test/807-method-handle-and-mr/expected.txt
diff --git a/test/990-method-handle-and-mr/info.txt b/test/807-method-handle-and-mr/info.txt
similarity index 100%
rename from test/990-method-handle-and-mr/info.txt
rename to test/807-method-handle-and-mr/info.txt
diff --git a/test/990-method-handle-and-mr/src/Main.java b/test/807-method-handle-and-mr/src/Main.java
similarity index 100%
rename from test/990-method-handle-and-mr/src/Main.java
rename to test/807-method-handle-and-mr/src/Main.java
diff --git a/test/912-classes/src-art/art/Test912.java b/test/912-classes/src-art/art/Test912.java
index ddfadf3..1a60185 100644
--- a/test/912-classes/src-art/art/Test912.java
+++ b/test/912-classes/src-art/art/Test912.java
@@ -398,6 +398,7 @@
     public static double dummy = Math.random();  // So it can't be compile-time initialized.
   }
 
+  @SuppressWarnings("RandomCast")
   private static class TestForInitFail {
     public static int dummy = ((int)Math.random())/0;  // So it throws when initializing.
   }
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index dfefce2..9e65a99 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -14,30 +14,13 @@
  * limitations under the License.
  */
 
-#include <inttypes.h>
+#include "source_transform.h"
 
-#include <cstdio>
-#include <cstring>
-#include <iostream>
-#include <vector>
+#include "jni.h"
 
 #include "android-base/stringprintf.h"
-#include "jni.h"
 #include "jvmti.h"
-
-#include "base/macros.h"
-#include "bytecode_utils.h"
-#include "dex/code_item_accessors-inl.h"
-#include "dex/art_dex_file_loader.h"
-#include "dex/dex_file.h"
-#include "dex/dex_file_loader.h"
-#include "dex/dex_instruction.h"
-#include "jit/jit.h"
-#include "native_stack_dump.h"
-#include "runtime.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-current-inl.h"
-#include "thread_list.h"
+#include "scoped_local_ref.h"
 
 // Test infrastructure
 #include "jvmti_helper.h"
@@ -48,9 +31,18 @@
 
 constexpr bool kSkipInitialLoad = true;
 
+static void Println(JNIEnv* env, const char* msg) {
+  ScopedLocalRef<jclass> test_klass(env, env->FindClass("art/Test983"));
+  jmethodID println_method = env->GetStaticMethodID(test_klass.get(),
+                                                    "doPrintln",
+                                                    "(Ljava/lang/String;)V");
+  ScopedLocalRef<jstring> data(env, env->NewStringUTF(msg));
+  env->CallStaticVoidMethod(test_klass.get(), println_method, data.get());
+}
+
 // The hook we are using.
 void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
-                              JNIEnv* jni_env ATTRIBUTE_UNUSED,
+                              JNIEnv* env,
                               jclass class_being_redefined,
                               jobject loader ATTRIBUTE_UNUSED,
                               const char* name,
@@ -60,78 +52,24 @@
                               jint* new_class_data_len ATTRIBUTE_UNUSED,
                               unsigned char** new_class_data ATTRIBUTE_UNUSED) {
   if (kSkipInitialLoad && class_being_redefined == nullptr) {
-    // Something got loaded concurrently. Just ignore it for now.
+    // Something got loaded concurrently. Just ignore it for now. To make sure the test is
+    // repeatable we only care about things that come from RetransformClasses.
     return;
   }
-  std::cout << "Dex file hook for " << name << std::endl;
+  Println(env, android::base::StringPrintf("Dex file hook for %s", name).c_str());
   if (IsJVM()) {
     return;
   }
 
-  // Due to b/72402467 the class_data_len might just be an estimate.
-  CHECK_GE(static_cast<size_t>(class_data_len), sizeof(DexFile::Header));
-  const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(class_data);
-  uint32_t header_file_size = header->file_size_;
-  CHECK_LE(static_cast<jint>(header_file_size), class_data_len);
-  class_data_len = static_cast<jint>(header_file_size);
-
-  const ArtDexFileLoader dex_file_loader;
-  std::string error;
-  std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data,
-                                                          class_data_len,
-                                                          "fake_location.dex",
-                                                          /*location_checksum*/ 0,
-                                                          /*oat_dex_file*/ nullptr,
-                                                          /*verify*/ true,
-                                                          /*verify_checksum*/ true,
-                                                          &error));
-  if (dex.get() == nullptr) {
-    std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
-    return;
-  }
-  for (uint32_t i = 0; i < dex->NumClassDefs(); i++) {
-    const DexFile::ClassDef& def = dex->GetClassDef(i);
-    const uint8_t* data_item = dex->GetClassData(def);
-    if (data_item == nullptr) {
-      continue;
-    }
-    for (ClassDataItemIterator it(*dex, data_item); it.HasNext(); it.Next()) {
-      if (!it.IsAtMethod() || it.GetMethodCodeItem() == nullptr) {
-        continue;
-      }
-      for (const DexInstructionPcPair& pair :
-          art::CodeItemInstructionAccessor(*dex, it.GetMethodCodeItem())) {
-        const Instruction& inst = pair.Inst();
-        int forbiden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly);
-        if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER ||
-            (inst.GetVerifyExtraFlags() & forbiden_flags) != 0) {
-          std::cout << "Unexpected instruction found in " << dex->PrettyMethod(it.GetMemberIndex())
-                    << " [Dex PC: 0x" << std::hex << pair.DexPc() << std::dec << "] : "
-                    << inst.DumpString(dex.get()) << std::endl;
-          continue;
-        }
-      }
-    }
-  }
+  VerifyClassData(class_data_len, class_data);
 }
 
 // Get all capabilities except those related to retransformation.
-jint OnLoad(JavaVM* vm,
-            char* options ATTRIBUTE_UNUSED,
-            void* reserved ATTRIBUTE_UNUSED) {
-  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
-    printf("Unable to get jvmti env!\n");
-    return 1;
-  }
-  SetStandardCapabilities(jvmti_env);
+extern "C" JNIEXPORT void JNICALL Java_art_Test983_setupLoadHook(JNIEnv* env, jclass) {
   jvmtiEventCallbacks cb;
   memset(&cb, 0, sizeof(cb));
   cb.ClassFileLoadHook = CheckDexFileHook;
-  if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
-    printf("Unable to set class file load hook cb!\n");
-    return 1;
-  }
-  return 0;
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
 }
 
 }  // namespace Test983SourceTransformVerify
diff --git a/test/983-source-transform-verify/source_transform.h b/test/983-source-transform-verify/source_transform.h
index db9415a..2206498 100644
--- a/test/983-source-transform-verify/source_transform.h
+++ b/test/983-source-transform-verify/source_transform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -22,7 +22,7 @@
 namespace art {
 namespace Test983SourceTransformVerify {
 
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
+void VerifyClassData(jint class_data_len, const unsigned char* class_data);
 
 }  // namespace Test983SourceTransformVerify
 }  // namespace art
diff --git a/test/983-source-transform-verify/source_transform_art.cc b/test/983-source-transform-verify/source_transform_art.cc
new file mode 100644
index 0000000..5353370
--- /dev/null
+++ b/test/983-source-transform-verify/source_transform_art.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "source_transform.h"
+
+#include <inttypes.h>
+
+#include <memory>
+
+#include <android-base/logging.h>
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/art_dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_instruction.h"
+
+namespace art {
+namespace Test983SourceTransformVerify {
+
+// The hook we are using.
+void VerifyClassData(jint class_data_len, const unsigned char* class_data) {
+  // Due to b/72402467 the class_data_len might just be an estimate.
+  CHECK_GE(static_cast<size_t>(class_data_len), sizeof(DexFile::Header));
+  const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(class_data);
+  uint32_t header_file_size = header->file_size_;
+  CHECK_LE(static_cast<jint>(header_file_size), class_data_len);
+  class_data_len = static_cast<jint>(header_file_size);
+
+  const ArtDexFileLoader dex_file_loader;
+  std::string error;
+  std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data,
+                                                          class_data_len,
+                                                          "fake_location.dex",
+                                                          /*location_checksum*/ 0,
+                                                          /*oat_dex_file*/ nullptr,
+                                                          /*verify*/ true,
+                                                          /*verify_checksum*/ true,
+                                                          &error));
+  CHECK(dex.get() != nullptr) << "Failed to verify dex: " << error;
+  for (uint32_t i = 0; i < dex->NumClassDefs(); i++) {
+    const DexFile::ClassDef& def = dex->GetClassDef(i);
+    const uint8_t* data_item = dex->GetClassData(def);
+    if (data_item == nullptr) {
+      continue;
+    }
+    for (ClassDataItemIterator it(*dex, data_item); it.HasNext(); it.Next()) {
+      if (!it.IsAtMethod() || it.GetMethodCodeItem() == nullptr) {
+        continue;
+      }
+      for (const DexInstructionPcPair& pair :
+          art::CodeItemInstructionAccessor(*dex, it.GetMethodCodeItem())) {
+        const Instruction& inst = pair.Inst();
+        int forbidden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly);
+        if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER ||
+            (inst.GetVerifyExtraFlags() & forbidden_flags) != 0) {
+          LOG(FATAL) << "Unexpected instruction found in " << dex->PrettyMethod(it.GetMemberIndex())
+                     << " [Dex PC: 0x" << std::hex << pair.DexPc() << std::dec << "] : "
+                     << inst.DumpString(dex.get()) << std::endl;
+        }
+      }
+    }
+  }
+}
+
+}  // namespace Test983SourceTransformVerify
+}  // namespace art
diff --git a/test/983-source-transform-verify/source_transform_slicer.cc b/test/983-source-transform-verify/source_transform_slicer.cc
new file mode 100644
index 0000000..abf32e7
--- /dev/null
+++ b/test/983-source-transform-verify/source_transform_slicer.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "source_transform.h"
+
+#pragma clang diagnostic push
+// slicer defines its own CHECK. b/65422458
+#pragma push_macro("CHECK")
+#undef CHECK
+
+// Slicer's headers have code that triggers these warnings. b/65298177
+#pragma clang diagnostic ignored "-Wsign-compare"
+#include "reader.h"
+
+#pragma pop_macro("CHECK")
+#pragma clang diagnostic pop
+
+namespace art {
+namespace Test983SourceTransformVerify {
+
+// The hook we are using.
+void VerifyClassData(jint class_data_len, const unsigned char* class_data) {
+  dex::Reader reader(class_data, class_data_len);
+  reader.CreateFullIr();  // This will verify all bytecode.
+}
+
+}  // namespace Test983SourceTransformVerify
+}  // namespace art
diff --git a/test/983-source-transform-verify/src/art/Test983.java b/test/983-source-transform-verify/src/art/Test983.java
index faae96a..7dc47ab 100644
--- a/test/983-source-transform-verify/src/art/Test983.java
+++ b/test/983-source-transform-verify/src/art/Test983.java
@@ -27,7 +27,15 @@
     doTest();
   }
 
+  private native static void setupLoadHook();
+
+  /* called from JNI */
+  public static void doPrintln(String str) {
+    System.out.println(str);
+  }
+
   public static void doTest() {
+    setupLoadHook();
     Redefinition.enableCommonRetransformation(true);
     Redefinition.doCommonClassRetransformation(Transform.class);
     Redefinition.doCommonClassRetransformation(Object.class);
diff --git a/test/Android.bp b/test/Android.bp
index 5f39ffe..902f4ed 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -62,7 +62,7 @@
         "libvixld-arm",
         "libvixld-arm64",
         "libart-gtest",
-        "libdexfile",
+        "libdexfiled",
 
         "libbase",
         "libicuuc",
@@ -114,7 +114,7 @@
     shared_libs: [
         "libartd",
         "libartd-compiler",
-        "libdexfile",
+        "libdexfiled",
     ],
     static_libs: [
         "libgtest",
@@ -151,7 +151,7 @@
     shared_libs: [
         "libartd",
         "libartd-compiler",
-        "libdexfile",
+        "libdexfiled",
         "libbase",
         "libbacktrace",
     ],
@@ -238,6 +238,7 @@
         "931-agent-thread/agent_thread.cc",
         "933-misc-events/misc_events.cc",
         "945-obsolete-native/obsolete_native.cc",
+        "983-source-transform-verify/source_transform.cc",
         "984-obsolete-invoke/obsolete_invoke.cc",
         "986-native-method-bind/native_bind.cc",
         "987-agent-bind/agent_bind.cc",
@@ -288,20 +289,22 @@
         "909-attach-agent/attach.cc",
         "912-classes/classes_art.cc",
         "936-search-onload/search_onload.cc",
-        "983-source-transform-verify/source_transform.cc",
+        "983-source-transform-verify/source_transform_art.cc",
         "1940-ddms-ext/ddm_ext.cc",
         "1944-sudden-exit/sudden_exit.cc",
     ],
     shared_libs: [
         "libbase",
-        "libdexfile",
     ],
 }
 
 art_cc_test_library {
     name: "libtiagent",
     defaults: ["libtiagent-defaults"],
-    shared_libs: ["libart"],
+    shared_libs: [
+        "libart",
+        "libdexfile",
+    ],
 }
 
 art_cc_test_library {
@@ -310,24 +313,32 @@
         "art_debug_defaults",
         "libtiagent-defaults",
     ],
-    shared_libs: ["libartd"],
+    shared_libs: [
+        "libartd",
+        "libdexfiled",
+    ],
 }
 
-art_cc_test_library {
+cc_library_static {
     name: "libctstiagent",
     defaults: ["libtiagent-base-defaults"],
+    host_supported: false,
+    srcs: [
+        "983-source-transform-verify/source_transform_slicer.cc",
+    ],
     whole_static_libs: [
-        "libdexfile",
-        "libz",
-        "libziparchive",
+        "slicer",
+        "libz",  // for slicer (using adler32).
     ],
     static_libs: [
         "libbase",
-        "libcutils",
-        "libutils",
     ],
-    shared_libs: [
-        "liblog",
+    header_libs: [
+        // This is needed to resolve the base/ header file in libdexfile. Unfortunately there are
+        // many problems with how we export headers that are making doing this the 'right' way
+        // difficult.
+        // TODO: move those headers to art/ rather than under runtime.
+        "libart_runtime_headers",
     ],
     export_include_dirs: ["ti-agent"],
 }
@@ -367,11 +378,9 @@
         "art_defaults",
     ],
     srcs: [
-        "common/runtime_state.cc",
-        "common/stack_inspect.cc",
         "004-JniTest/jni_test.cc",
-        "004-SignalTest/signaltest.cc",
         "004-ReferenceMap/stack_walk_refmap_jni.cc",
+        "004-SignalTest/signaltest.cc",
         "004-StackWalk/stack_walk_jni.cc",
         "004-ThreadStress/thread_stress.cc",
         "004-UnsafeTest/unsafe_test.cc",
@@ -388,6 +397,7 @@
         "154-gc-loop/heap_interface.cc",
         "167-visit-locks/visit_locks.cc",
         "169-threadgroup-jni/jni_daemon_thread.cc",
+        "1945-proxy-method-arguments/get_args.cc",
         "203-multi-checkpoint/multi_checkpoint.cc",
         "305-other-fault-handler/fault_handler.cc",
         "454-get-vreg/get_vreg_jni.cc",
@@ -411,9 +421,10 @@
         "667-jit-jni-stub/jit_jni_stub_test.cc",
         "674-hiddenapi/hiddenapi.cc",
         "708-jit-cache-churn/jit.cc",
+        "common/runtime_state.cc",
+        "common/stack_inspect.cc",
     ],
     shared_libs: [
-        "libdexfile",
         "libbacktrace",
         "libbase",
         "libnativehelper",
@@ -423,7 +434,10 @@
 art_cc_test_library {
     name: "libarttest",
     defaults: ["libarttest-defaults"],
-    shared_libs: ["libart"],
+    shared_libs: [
+        "libart",
+        "libdexfile",
+    ],
 }
 
 art_cc_test_library {
@@ -432,7 +446,10 @@
         "art_debug_defaults",
         "libarttest-defaults",
     ],
-    shared_libs: ["libartd"],
+    shared_libs: [
+        "libartd",
+        "libdexfiled",
+    ],
 }
 
 art_cc_test_library {
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 5200db5..1184ced 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -866,7 +866,7 @@
     fi
 
     # System libraries needed by libarttestd.so
-    PUBLIC_LIBS=libart.so:libartd.so:libc++.so:libbacktrace.so:libdexfile.so:libbase.so:libnativehelper.so
+    PUBLIC_LIBS=libart.so:libartd.so:libc++.so:libbacktrace.so:libdexfile.so:libdexfiled.so:libbase.so:libnativehelper.so
 
     # Create a script with the command. The command can get longer than the longest
     # allowed adb command and there is no way to get the exit status from a adb shell
diff --git a/test/knownfailures.json b/test/knownfailures.json
index b483b93..ddf9098 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -377,12 +377,6 @@
         "variant": "jvmti-stress & jit | redefine-stress & jit"
     },
     {
-        "test_patterns": ["674-hiddenapi"],
-        "description": ["hiddenapi test is failing with redefine stress cdex"],
-        "bug": "http://b/72610009",
-        "variant": "redefine-stress & cdex-fast"
-    },
-    {
         "test_patterns": ["616-cha"],
         "description": ["The test assumes a boot image exists."],
         "bug": "http://b/34193647",
@@ -423,21 +417,13 @@
         "variant": "redefine-stress & speed-profile | jvmti-stress & speed-profile"
     },
     {
-        "tests": [
-            "714-invoke-custom-lambda-metafactory",
-            "950-redefine-intrinsic",
-            "951-threaded-obsolete",
-            "952-invoke-custom",
-            "952-invoke-custom-kinds",
-            "953-invoke-polymorphic-compiler",
-            "954-invoke-polymorphic-verifier",
-            "955-methodhandles-smali",
-            "956-methodhandles",
-            "957-methodhandle-transforms",
-            "958-methodhandle-stackframe",
-            "959-invoke-polymorphic-accessors",
-            "979-const-method-handle",
-            "990-method-handle-and-mr"
+        "test_patterns": [
+            ".*invoke-custom.*",
+            ".*invoke-polymorphic.*",
+            ".*methodhandle.*",
+            ".*method-handle.*",
+            ".*varhandle.*",
+            ".*var-handle.*"
         ],
         "description": [
             "Tests that use invoke-polymorphic/invoke-custom which is not yet supported by",
@@ -460,9 +446,22 @@
     },
     {
         "tests": [
+            "132-daemon-locks-shutdown",
+            "607-daemon-stress",
+            "602-deoptimizeable",
+            "121-simple-suspend-check",
+            "083-compiler-regressions"
+        ],
+        "description": ["Tests that have failed on redefine stress for unknown reasons"],
+        "bug": "b/73177368",
+        "variant": "redefine-stress"
+    },
+    {
+        "tests": [
             "097-duplicate-method",
             "138-duplicate-classes-check2",
             "159-app-image-fields",
+            "674-hiddenapi",
             "649-vdex-duplicate-method",
             "804-class-extends-itself",
             "921-hello-failure"
@@ -481,6 +480,7 @@
             "626-const-class-linking",
             "629-vdex-speed",
             "647-jni-get-field-id",
+            "674-hiddenapi",
             "944-transform-classloaders"
         ],
         "description": [
@@ -494,7 +494,7 @@
             "004-ThreadStress"
         ],
         "description": "The thread stress test just takes too long with field-stress",
-        "variant": "jvmti-stress | field-stress | step-stress"
+        "variant": "jvmti-stress | field-stress | step-stress | redefine-stress"
     },
     {
         "tests": [
@@ -653,11 +653,6 @@
         "description": ["Test is designed to only check --compiler-filter=speed"]
     },
     {
-        "test_patterns": [".*"],
-        "description": ["Tests are timing out for weeks now, disable to fix."],
-        "variant": "cdex-fast & redefine-stress"
-    },
-    {
         "tests": "674-HelloWorld-Dm",
         "variant": "target",
         "description": ["Requires zip, which isn't available on device"]
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 3d173f5..4329ad4 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -110,6 +110,7 @@
 total_test_count = 0
 verbose = False
 dry_run = False
+ignore_skips = False
 build = False
 gdb = False
 gdb_arg = ''
@@ -710,6 +711,8 @@
     return True
   if test in env.EXTRA_DISABLED_TESTS:
     return True
+  if ignore_skips:
+    return False
   variants_list = DISABLED_TEST_CONTAINER.get(test, {})
   for variants in variants_list:
     variants_present = True
@@ -878,6 +881,7 @@
 def parse_option():
   global verbose
   global dry_run
+  global ignore_skips
   global n_thread
   global build
   global gdb
@@ -897,6 +901,8 @@
   parser.add_argument('--dry-run', action='store_true', dest='dry_run')
   parser.add_argument("--skip", action="append", dest="skips", default=[],
                       help="Skip the given test in all circumstances.")
+  parser.add_argument("--no-skips", dest="ignore_skips", action="store_true", default=False,
+                      help="Don't skip any run-test configurations listed in knownfailures.json.")
   parser.add_argument('--no-build-dependencies',
                       action='store_false', dest='build',
                       help="Don't build dependencies under any circumstances. This is the " +
@@ -935,6 +941,7 @@
     verbose = True
   if options['n_thread']:
     n_thread = max(1, options['n_thread'])
+  ignore_skips = options['ignore_skips']
   if options['dry_run']:
     dry_run = True
     verbose = True
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 9a7352e..bfd165d 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -28,7 +28,6 @@
 #include "901-hello-ti-agent/basics.h"
 #include "909-attach-agent/attach.h"
 #include "936-search-onload/search_onload.h"
-#include "983-source-transform-verify/source_transform.h"
 #include "1919-vminit-thread-start-timing/vminit.h"
 
 namespace art {
@@ -83,7 +82,6 @@
   { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr },
   { "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr },
   { "943-private-recursive-jit", common_redefine::OnLoad, nullptr },
-  { "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr },
   { "1919-vminit-thread-start-timing", Test1919VMInitThreadStart::OnLoad, nullptr },
 };
 
diff --git a/tools/amm/AmmTest/AndroidManifest.xml b/tools/amm/AmmTest/AndroidManifest.xml
new file mode 100644
index 0000000..16529bc
--- /dev/null
+++ b/tools/amm/AmmTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest
+  xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.amm.test">
+
+  <application
+    android:label="AmmTest"
+    android:debuggable="true">
+
+    <activity android:name="com.android.amm.test.MainActivity">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+</manifest>
diff --git a/tools/amm/AmmTest/aahat.png b/tools/amm/AmmTest/aahat.png
new file mode 100644
index 0000000..01b92f4
--- /dev/null
+++ b/tools/amm/AmmTest/aahat.png
Binary files differ
diff --git a/tools/amm/AmmTest/jni/ammtest.c b/tools/amm/AmmTest/jni/ammtest.c
new file mode 100644
index 0000000..9d48475
--- /dev/null
+++ b/tools/amm/AmmTest/jni/ammtest.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+// A large uninitialized array gets put in the .bss section:
+char uninit[3 * 4096];
+
+// A large initialized array gets put in the .data section:
+char init[2 * 4096] =
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.."
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789..";
+
+// A large constant initialized array gets put in the .rodata section:
+const char cinit[1 * 4096] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.."
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789..";
+
+JNIEXPORT jint JNICALL
+Java_com_android_amm_test_SoCodeUse_nGetANumber(JNIEnv* env, jclass cls) {
+  (void) env;
+  (void) cls;
+
+  uninit[4096] = init[123] + cinit[123];
+  return 42;
+}
+
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/BitmapUse.java b/tools/amm/AmmTest/src/com/android/amm/test/BitmapUse.java
new file mode 100644
index 0000000..d8eba2e
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/BitmapUse.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+/**
+ * Exercise loading of a bitmap.
+ */
+class BitmapUse {
+
+  private Bitmap mBitmap;
+
+  public BitmapUse() {
+    ClassLoader loader = BitmapUse.class.getClassLoader();
+    mBitmap = BitmapFactory.decodeStream(loader.getResourceAsStream("aahat.png"), null, null);
+  }
+}
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/MainActivity.java b/tools/amm/AmmTest/src/com/android/amm/test/MainActivity.java
new file mode 100644
index 0000000..4577f4b
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/MainActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+
+public class MainActivity extends Activity {
+
+  private BitmapUse mBitmapUse;
+  private SoCodeUse mSoCodeUse;
+  private TextureViewUse mTextureViewUse;
+  private SurfaceViewUse mSurfaceViewUse;
+  private ThreadedRendererUse mThreadedRendererUse;
+
+  @Override
+  public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    mBitmapUse = new BitmapUse();
+    mSoCodeUse = new SoCodeUse();
+
+    LinearLayout ll = new LinearLayout(this);
+    mTextureViewUse = new TextureViewUse(this, ll, 200, 500);
+    mSurfaceViewUse = new SurfaceViewUse(this, ll, 240, 250);
+    setContentView(ll);
+
+    mThreadedRendererUse = new ThreadedRendererUse(this, 122, 152);
+  }
+}
+
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/SoCodeUse.java b/tools/amm/AmmTest/src/com/android/amm/test/SoCodeUse.java
new file mode 100644
index 0000000..9636c0f
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/SoCodeUse.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+class SoCodeUse {
+  private int value;
+
+  public SoCodeUse() {
+    // TODO: Figure out how to cause the native library to be unloaded when
+    // the SoCodeUse instance goes away?
+    System.loadLibrary("ammtestjni");
+    value = nGetANumber();
+  }
+
+  private static native int nGetANumber();
+}
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/SurfaceViewUse.java b/tools/amm/AmmTest/src/com/android/amm/test/SurfaceViewUse.java
new file mode 100644
index 0000000..0c17c77
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/SurfaceViewUse.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+
+class SurfaceViewUse {
+
+  private SurfaceView mSurfaceView;
+
+  /**
+   * Constructs a SurfaceView object with given dimensions.
+   * The surface view is added to the given ViewGroup object, which should be
+   * included in the main display.
+   */
+  public SurfaceViewUse(Context context, ViewGroup vg, int width, int height) {
+    mSurfaceView = new SurfaceView(context);
+    vg.addView(mSurfaceView, width, height);
+    mSurfaceView.post(new CycleRunnable());
+  }
+
+  // To force as many graphics buffers as will ever be used to actually be
+  // used, we cycle the color of the surface view a handful of times right
+  // when things start up.
+  private class CycleRunnable implements Runnable {
+    private int mCycles = 0;
+    private int mRed = 255;
+    private int mGreen = 0;
+    private int mBlue = 255;
+
+    public void run() {
+      if (mCycles < 10) {
+        mCycles++;
+        updateSurfaceView();
+        mSurfaceView.post(this);
+      }
+    }
+
+    private void updateSurfaceView() {
+      SurfaceHolder holder = mSurfaceView.getHolder();
+      Canvas canvas = holder.lockHardwareCanvas();
+      if (canvas != null) {
+        canvas.drawRGB(mRed, mGreen, mBlue);
+        int tmp = mRed;
+        holder.unlockCanvasAndPost(canvas);
+        mRed = mGreen;
+        mGreen = mBlue;
+        mBlue = tmp;
+      }
+    }
+  }
+}
+
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/TextureViewUse.java b/tools/amm/AmmTest/src/com/android/amm/test/TextureViewUse.java
new file mode 100644
index 0000000..51ffcd2
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/TextureViewUse.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.view.TextureView;
+import android.view.ViewGroup;
+
+class TextureViewUse {
+
+  private TextureView mTextureView;
+
+  /**
+   * Constructs a TextureView object with given dimensions.
+   * The texture view is added to the given ViewGroup object, which should be
+   * included in the main display.
+   */
+  public TextureViewUse(Context context, ViewGroup vg, int width, int height) {
+    mTextureView = new TextureView(context);
+    vg.addView(mTextureView, width, height);
+    mTextureView.post(new CycleRunnable());
+  }
+
+  // To force as many graphics buffers as will ever be used to actually be
+  // used, we cycle the color of the texture view a handful of times right
+  // when things start up.
+  private class CycleRunnable implements Runnable {
+    private int mCycles = 0;
+    private int mRed = 255;
+    private int mGreen = 255;
+    private int mBlue = 0;
+
+    public void run() {
+      if (mCycles < 10) {
+        mCycles++;
+        updateTextureView();
+        mTextureView.post(this);
+      }
+    }
+
+    private void updateTextureView() {
+      Canvas canvas = mTextureView.lockCanvas();
+      if (canvas != null) {
+        canvas.drawRGB(mRed, mGreen, mBlue);
+        int tmp = mRed;
+        mTextureView.unlockCanvasAndPost(canvas);
+        mRed = mGreen;
+        mGreen = mBlue;
+        mBlue = tmp;
+      }
+    }
+  }
+}
+
diff --git a/tools/amm/AmmTest/src/com/android/amm/test/ThreadedRendererUse.java b/tools/amm/AmmTest/src/com/android/amm/test/ThreadedRendererUse.java
new file mode 100644
index 0000000..9c25612
--- /dev/null
+++ b/tools/amm/AmmTest/src/com/android/amm/test/ThreadedRendererUse.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.amm.test;
+
+import android.content.Context;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+class ThreadedRendererUse {
+
+  private TextView mTextView;
+
+  /**
+   * Cause a threaded renderer EGL allocation to be used, with given
+   * dimensions.
+   */
+  public ThreadedRendererUse(Context context, int width, int height) {
+    mTextView = new TextView(context);
+    mTextView.setText("TRU");
+    mTextView.setBackgroundColor(0xffff0000);
+
+    // Adding a view to the WindowManager (as opposed to the app's root view
+    // hierarchy) causes a ThreadedRenderer and EGL allocations under the cover.
+    // We use a TextView here to trigger the use case, but we could use any
+    // other kind of view as well.
+    WindowManager wm = context.getSystemService(WindowManager.class);
+    WindowManager.LayoutParams layout = new WindowManager.LayoutParams();
+    layout.width = width;
+    layout.height = height;
+    wm.addView(mTextView, layout);
+
+    mTextView.post(new CycleRunnable());
+  }
+
+  // To force as many graphics buffers as will ever be used to actually be
+  // used, we cycle the text of the text view a handful of times right
+  // when things start up.
+  private class CycleRunnable implements Runnable {
+    private int mCycles = 0;
+
+    public void run() {
+      if (mCycles < 10) {
+        mCycles++;
+        mTextView.setText("TRU " + mCycles);
+        mTextView.post(this);
+      }
+    }
+  }
+}
+
diff --git a/tools/amm/Android.mk b/tools/amm/Android.mk
new file mode 100644
index 0000000..47030c5
--- /dev/null
+++ b/tools/amm/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# --- ammtestjni.so -------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libammtestjni
+LOCAL_SRC_FILES := $(call all-c-files-under, AmmTest/jni)
+LOCAL_SDK_VERSION := current
+include $(BUILD_SHARED_LIBRARY)
+
+# --- AmmTest.apk --------------
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := AmmTest
+LOCAL_MODULE_TAGS := samples tests
+LOCAL_SRC_FILES := $(call all-java-files-under, AmmTest/src)
+LOCAL_SDK_VERSION := current
+LOCAL_JNI_SHARED_LIBRARIES := libammtestjni
+LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/AmmTest/aahat.png
+LOCAL_MANIFEST_FILE := AmmTest/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
diff --git a/tools/amm/README.md b/tools/amm/README.md
new file mode 100644
index 0000000..17f94a8
--- /dev/null
+++ b/tools/amm/README.md
@@ -0,0 +1,16 @@
+# Actionable Memory Metric
+
+The goal of the actionable memory metric (AMM) is to provide a view of an
+application's memory use that application developers can track, understand,
+and control. AMM can be thought of as a Java heap dump augmented with models
+for non-Java allocations that app developers have some control of.
+
+There are two components of the actionable memory metric:
+1. The value of the metric.
+2. An actionable breakdown of the value of the metric.
+
+The metric is made up of a collection of separate models for different
+categories of memory use. Each model contributes to the value and actionable
+breakdown of the overall metric.
+
+See models/ for a list of models proposed for the actionable memory metric.
diff --git a/tools/amm/models/Bitmap.md b/tools/amm/models/Bitmap.md
new file mode 100644
index 0000000..49a0b9d
--- /dev/null
+++ b/tools/amm/models/Bitmap.md
@@ -0,0 +1,15 @@
+# Bitmap Model
+
+The value of the Bitmap model is the sum of bytes used for native pixel data
+of instances of `android.graphics.Bitmap`. It is calculated by summing for
+each instance `x` of `android.graphics.Bitmap`:
+
+    x.getAllocationByteCount()
+
+The actionable breakdown of the Bitmap model is a breakdown by
+`android.graphics.Bitmap` instance, including width, height, and ideally a
+thumbnail image of each bitmap.
+
+For example, an 800 x 600 bitmap instance using the `ARGB_8888` pixel format
+with native pixel data will be shown as an 800 x 600 bitmap instance taking up
+1875 kB.
diff --git a/tools/amm/models/DexCode.md b/tools/amm/models/DexCode.md
new file mode 100644
index 0000000..a907280
--- /dev/null
+++ b/tools/amm/models/DexCode.md
@@ -0,0 +1,17 @@
+# Dex Code Model
+
+The value of the Dex Code model is the sum of the original uncompressed file
+sizes of all loaded dex files. It is calculated using the best approximation
+of the dex file size available to us on device. On Android O, for example,
+this can be approximated as the virtual size of the corresponding memory
+mapped `.vdex` file read from `/proc/self/maps`. Different Android platform
+versions and scenarios may require different approximations.
+
+The actionable breakdown of the dex code model is a breakdown by
+`dalvik.system.DexFile` instance. Further breakdown of individual dex files
+can be achieved using tools such as dexdump.
+
+For example, for an application `AmmTest.apk` that has a single `classes.dex` file
+that is 500 KB uncompressed, the `DexFile` instance for
+`/data/app/com.android.amm.test-_uHI4CJWpeoztbjN6Tr-Nw==/base.apk` is shown as
+Taking up 500 KB (or the best available approximation thereof).
diff --git a/tools/amm/models/Graphics.md b/tools/amm/models/Graphics.md
new file mode 100644
index 0000000..b327961
--- /dev/null
+++ b/tools/amm/models/Graphics.md
@@ -0,0 +1,22 @@
+# Graphics Models
+
+There are three components to the graphics model, each modeling EGL memory
+use:
+1. For each `android.view.TextureView` instance:
+    2 * (4 * width * height)
+
+2. For each `android.view.Surface$HwuiContext` instance:
+    3 * (4 * width * height)
+
+3. For each initialized `android.view.ThreadedRenderer`:
+    3 * (4 * width * height)
+
+Note: 4 is the number of bytes per pixel. 2 or 3 is the maximum number of
+buffers that may be allocated.
+
+The actionable breakdown is the breakdown by `TextureView`,
+`Surface$HwuiContext` and `ThreadedRenderer` instance, with further details
+about the width and height associated with each instance.
+
+For example, an application with a single 64x256 `TextureView` instance will
+be shown as taking up 128 KB.
diff --git a/tools/amm/models/JavaHeap.md b/tools/amm/models/JavaHeap.md
new file mode 100644
index 0000000..c34c186
--- /dev/null
+++ b/tools/amm/models/JavaHeap.md
@@ -0,0 +1,8 @@
+# Java Heap Model
+
+The value of the Java heap model is the sum of bytes of Java objects allocated
+on the Java heap. It can be calculated using:
+
+    Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
+
+A Java heap dump is used for an actionable breakdown of the Java heap.
diff --git a/tools/amm/models/SoCode.md b/tools/amm/models/SoCode.md
new file mode 100644
index 0000000..5d3184e
--- /dev/null
+++ b/tools/amm/models/SoCode.md
@@ -0,0 +1,17 @@
+# Shared Native Code Model
+
+The value of the Shared Native Code model is the sum of the virtual memory
+sizes of all loaded `.so` files. It is calculated by reading `/proc/self/maps`.
+
+The actionable breakdown of the shared native code model is a breakdown by
+library name. Unfortunately, due to technical limitations, this does not
+include information about what caused a library to be loaded, whether the
+library was loaded by the app or the platform, the library dependency graph,
+or what is causing a library to remain loaded. Individual `.so` files can be
+further broken down using tools such as `readelf`.
+
+For example, for an application `AmmTest.apk` that includes `libammtestjni.so` as a
+native library that loads 36 KB worth of memory regions, `BaseClassLoader` will
+be shown with library
+`/data/app/com.android.amm.test-_uHI4CJWpeoztbjN6Tr-Nw==/lib/arm64/libammtestjni.so`
+taking up 36 KB.
diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp
index f9824f1..af87d31 100644
--- a/tools/hiddenapi/Android.bp
+++ b/tools/hiddenapi/Android.bp
@@ -30,7 +30,6 @@
     },
 
     shared_libs: [
-        "libdexfile",
         "libbase",
     ],
 }
@@ -40,6 +39,7 @@
     defaults: ["hiddenapi-defaults"],
     shared_libs: [
         "libart",
+        "libdexfile",
     ],
 }
 
@@ -51,6 +51,7 @@
     ],
     shared_libs: [
         "libartd",
+        "libdexfiled",
     ],
 }
 
diff --git a/tools/public.libraries.buildbot.txt b/tools/public.libraries.buildbot.txt
index 734fd1e..de636a8 100644
--- a/tools/public.libraries.buildbot.txt
+++ b/tools/public.libraries.buildbot.txt
@@ -1,6 +1,7 @@
 libart.so
 libartd.so
 libdexfile.so
+libdexfiled.so
 libbacktrace.so
 libc.so
 libc++.so