Merge "Use FdFile::Copy() in dex2oat for better error checking."
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index b580049..6f48779 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -94,7 +94,7 @@
                                               /*low_4gb*/false,
                                               &error_msg));
     CHECK(ef.get() != nullptr) << error_msg;
-    CHECK(ef->Load(false, /*low_4gb*/false, &error_msg)) << error_msg;
+    CHECK(ef->Load(file.get(), false, /*low_4gb*/false, &error_msg)) << error_msg;
     EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata"));
     EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec"));
     EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword"));
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 13c73dc..83c7332 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1492,10 +1492,15 @@
     // Calculate how big the intern table will be after being serialized.
     InternTable* const intern_table = image_info.intern_table_.get();
     CHECK_EQ(intern_table->WeakSize(), 0u) << " should have strong interned all the strings";
-    image_info.intern_table_bytes_ = intern_table->WriteToMemory(nullptr);
+    if (intern_table->StrongSize() != 0u) {
+      image_info.intern_table_bytes_ = intern_table->WriteToMemory(nullptr);
+    }
     // Calculate the size of the class table.
     ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
-    image_info.class_table_bytes_ += image_info.class_table_->WriteToMemory(nullptr);
+    DCHECK_EQ(image_info.class_table_->NumZygoteClasses(), 0u);
+    if (image_info.class_table_->NumNonZygoteClasses() != 0u) {
+      image_info.class_table_bytes_ += image_info.class_table_->WriteToMemory(nullptr);
+    }
   }
 
   // Calculate bin slot offsets.
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index f3eb663..c79bf92 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -442,7 +442,7 @@
     return ERROR_OAT_FILE;
   }
 
-  const std::string& file_path = oat_in->GetFile().GetPath();
+  const std::string& file_path = oat_in->GetFilePath();
 
   const OatHeader* oat_header = GetOatHeader(oat_in);
   if (oat_header == nullptr) {
@@ -846,7 +846,7 @@
   }
   OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset);
   if (!oat_header->IsValid()) {
-    LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header";
+    LOG(ERROR) << "Elf file " << oat_file->GetFilePath() << " has an invalid oat header";
     return false;
   }
   oat_header->RelocateOat(delta_);
@@ -854,10 +854,11 @@
 }
 
 bool PatchOat::PatchElf() {
-  if (oat_file_->Is64Bit())
+  if (oat_file_->Is64Bit()) {
     return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64());
-  else
+  } else {
     return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32());
+  }
 }
 
 template <typename ElfFileImpl>
diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h
index 12d3be7..f24a862 100644
--- a/runtime/base/hash_set.h
+++ b/runtime/base/hash_set.h
@@ -296,7 +296,7 @@
     return const_iterator(this, NumBuckets());
   }
 
-  bool Empty() {
+  bool Empty() const {
     return Size() == 0;
   }
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index eb2316b..239cdae 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -316,7 +316,6 @@
 ClassLinker::ClassLinker(InternTable* intern_table)
     // dex_lock_ is recursive as it may be used in stack dumping.
     : dex_lock_("ClassLinker dex lock", kDexLock),
-      dex_cache_boot_image_class_lookup_required_(false),
       failed_dex_cache_class_lookups_(0),
       class_roots_(nullptr),
       array_iftable_(nullptr),
@@ -969,7 +968,6 @@
       return false;
     }
   }
-  dex_cache_boot_image_class_lookup_required_ = true;
   std::vector<const OatFile*> oat_files =
       runtime->GetOatFileManager().RegisterImageOatFiles(spaces);
   DCHECK(!oat_files.empty());
@@ -1256,7 +1254,6 @@
     // Add image classes into the class table for the class loader, and fixup the dex caches and
     // class loader fields.
     WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
-    ClassTable* table = InsertClassTableForClassLoader(class_loader.Get());
     // Dex cache array fixup is all or nothing, we must reject app images that have mixed since we
     // rely on clobering the dex cache arrays in the image to forward to bss.
     size_t num_dex_caches_with_bss_arrays = 0;
@@ -1392,103 +1389,42 @@
         StackHandleScope<1> hs3(self);
         RegisterDexFileLocked(*dex_file, hs3.NewHandle(dex_cache));
       }
-      GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes();
-      const size_t num_types = dex_cache->NumResolvedTypes();
-      if (new_class_set == nullptr) {
-        for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
-          // The image space is not yet added to the heap, avoid read barriers.
-          mirror::Class* klass = types[j].Read();
-          // There may also be boot image classes,
-          if (space->HasAddress(klass)) {
-            DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
-            // Update the class loader from the one in the image class loader to the one that loaded
-            // the app image.
-            klass->SetClassLoader(class_loader.Get());
-            // The resolved type could be from another dex cache, go through the dex cache just in
-            // case. May be null for array classes.
-            if (klass->GetDexCacheStrings() != nullptr) {
-              DCHECK(!klass->IsArrayClass());
-              klass->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
-            }
-            // If there are multiple dex caches, there may be the same class multiple times
-            // in different dex caches. Check for this since inserting will add duplicates
-            // otherwise.
-            if (num_dex_caches > 1) {
-              mirror::Class* existing = table->LookupByDescriptor(klass);
-              if (existing != nullptr) {
-                DCHECK_EQ(existing, klass) << PrettyClass(klass);
-              } else {
-                table->Insert(klass);
-              }
-            } else {
-              table->Insert(klass);
-            }
-            // Double checked VLOG to avoid overhead.
-            if (VLOG_IS_ON(image)) {
-              VLOG(image) << PrettyClass(klass) << " " << klass->GetStatus();
-              if (!klass->IsArrayClass()) {
-                VLOG(image) << "From " << klass->GetDexCache()->GetDexFile()->GetBaseLocation();
-              }
-              VLOG(image) << "Direct methods";
-              for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) {
-                VLOG(image) << PrettyMethod(&m);
-              }
-              VLOG(image) << "Virtual methods";
-              for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) {
-                VLOG(image) << PrettyMethod(&m);
-              }
-            }
-          } else {
-            DCHECK(klass == nullptr || heap->ObjectIsInBootImageSpace(klass))
-                << klass << " " << PrettyClass(klass);
-          }
-        }
-      }
       if (kIsDebugBuild) {
+        CHECK(new_class_set != nullptr);
+        GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes();
+        const size_t num_types = dex_cache->NumResolvedTypes();
         for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
           // The image space is not yet added to the heap, avoid read barriers.
           mirror::Class* klass = types[j].Read();
           if (space->HasAddress(klass)) {
             DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
-            if (kIsDebugBuild) {
-              if (new_class_set != nullptr) {
-                auto it = new_class_set->Find(GcRoot<mirror::Class>(klass));
-                DCHECK(it != new_class_set->end());
-                DCHECK_EQ(it->Read(), klass);
-                mirror::Class* super_class = klass->GetSuperClass();
-                if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) {
-                  auto it2 = new_class_set->Find(GcRoot<mirror::Class>(super_class));
-                  DCHECK(it2 != new_class_set->end());
-                  DCHECK_EQ(it2->Read(), super_class);
-                }
-              } else {
-                DCHECK_EQ(table->LookupByDescriptor(klass), klass);
-                mirror::Class* super_class = klass->GetSuperClass();
-                if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) {
-                  CHECK_EQ(table->LookupByDescriptor(super_class), super_class);
-                }
+            auto it = new_class_set->Find(GcRoot<mirror::Class>(klass));
+            DCHECK(it != new_class_set->end());
+            DCHECK_EQ(it->Read(), klass);
+            mirror::Class* super_class = klass->GetSuperClass();
+            if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) {
+              auto it2 = new_class_set->Find(GcRoot<mirror::Class>(super_class));
+              DCHECK(it2 != new_class_set->end());
+              DCHECK_EQ(it2->Read(), super_class);
+            }
+            for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) {
+              const void* code = m.GetEntryPointFromQuickCompiledCode();
+              const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
+              if (!IsQuickResolutionStub(code) &&
+                  !IsQuickGenericJniStub(code) &&
+                  !IsQuickToInterpreterBridge(code) &&
+                  !m.IsNative()) {
+                DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
               }
             }
-            if (kIsDebugBuild) {
-              for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) {
-                const void* code = m.GetEntryPointFromQuickCompiledCode();
-                const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
-                if (!IsQuickResolutionStub(code) &&
-                    !IsQuickGenericJniStub(code) &&
-                    !IsQuickToInterpreterBridge(code) &&
-                    !m.IsNative()) {
-                  DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
-                }
-              }
-              for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) {
-                const void* code = m.GetEntryPointFromQuickCompiledCode();
-                const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
-                if (!IsQuickResolutionStub(code) &&
-                    !IsQuickGenericJniStub(code) &&
-                    !IsQuickToInterpreterBridge(code) &&
-                    !m.IsNative()) {
-                  DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
-                }
+            for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) {
+              const void* code = m.GetEntryPointFromQuickCompiledCode();
+              const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
+              if (!IsQuickResolutionStub(code) &&
+                  !IsQuickGenericJniStub(code) &&
+                  !IsQuickToInterpreterBridge(code) &&
+                  !m.IsNative()) {
+                DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
               }
             }
           }
@@ -1805,9 +1741,6 @@
     temp_set = ClassTable::ClassSet(space->Begin() + class_table_section.Offset(),
                                     /*make copy*/false,
                                     &read_count);
-    if (!app_image) {
-      dex_cache_boot_image_class_lookup_required_ = false;
-    }
     VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2);
   }
   if (app_image) {
@@ -1815,7 +1748,7 @@
     if (!UpdateAppImageClassLoadersAndDexCaches(space,
                                                 class_loader,
                                                 dex_caches,
-                                                added_class_table ? &temp_set : nullptr,
+                                                &temp_set,
                                                 /*out*/&forward_dex_cache_arrays,
                                                 /*out*/error_msg)) {
       return false;
@@ -1825,10 +1758,8 @@
     UpdateClassLoaderAndResolvedStringsVisitor visitor(space,
                                                        class_loader.Get(),
                                                        forward_dex_cache_arrays);
-    if (added_class_table) {
-      for (GcRoot<mirror::Class>& root : temp_set) {
-        visitor(root.Read());
-      }
+    for (GcRoot<mirror::Class>& root : temp_set) {
+      visitor(root.Read());
     }
     // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss.
     // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and
@@ -1962,9 +1893,6 @@
 }
 
 void ClassLinker::VisitClasses(ClassVisitor* visitor) {
-  if (dex_cache_boot_image_class_lookup_required_) {
-    AddBootImageClassesToClassTable();
-  }
   Thread* const self = Thread::Current();
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
   // Not safe to have thread suspension when we are holding a lock.
@@ -3608,17 +3536,6 @@
     if (existing != nullptr) {
       return existing;
     }
-    if (kIsDebugBuild &&
-        !klass->IsTemp() &&
-        class_loader == nullptr &&
-        dex_cache_boot_image_class_lookup_required_) {
-      // Check a class loaded with the system class loader matches one in the image if the class
-      // is in the image.
-      existing = LookupClassFromBootImage(descriptor);
-      if (existing != nullptr) {
-        CHECK_EQ(klass, existing);
-      }
-    }
     VerifyObject(klass);
     class_table->InsertWithHash(klass, hash);
     if (class_loader != nullptr) {
@@ -3658,90 +3575,15 @@
                                         const char* descriptor,
                                         size_t hash,
                                         mirror::ClassLoader* class_loader) {
-  {
-    ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
-    ClassTable* const class_table = ClassTableForClassLoader(class_loader);
-    if (class_table != nullptr) {
-      mirror::Class* result = class_table->Lookup(descriptor, hash);
-      if (result != nullptr) {
-        return result;
-      }
+  ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+  ClassTable* const class_table = ClassTableForClassLoader(class_loader);
+  if (class_table != nullptr) {
+    mirror::Class* result = class_table->Lookup(descriptor, hash);
+    if (result != nullptr) {
+      return result;
     }
   }
-  if (class_loader != nullptr || !dex_cache_boot_image_class_lookup_required_) {
-    return nullptr;
-  }
-  // Lookup failed but need to search dex_caches_.
-  mirror::Class* result = LookupClassFromBootImage(descriptor);
-  if (result != nullptr) {
-    result = InsertClass(descriptor, result, hash);
-  } else {
-    // Searching the image dex files/caches failed, we don't want to get into this situation
-    // often as map searches are faster, so after kMaxFailedDexCacheLookups move all image
-    // classes into the class table.
-    constexpr uint32_t kMaxFailedDexCacheLookups = 1000;
-    if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
-      AddBootImageClassesToClassTable();
-    }
-  }
-  return result;
-}
-
-static std::vector<mirror::ObjectArray<mirror::DexCache>*> GetImageDexCaches(
-    std::vector<gc::space::ImageSpace*> image_spaces) REQUIRES_SHARED(Locks::mutator_lock_) {
-  CHECK(!image_spaces.empty());
-  std::vector<mirror::ObjectArray<mirror::DexCache>*> dex_caches_vector;
-  for (gc::space::ImageSpace* image_space : image_spaces) {
-    mirror::Object* root = image_space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
-    DCHECK(root != nullptr);
-    dex_caches_vector.push_back(root->AsObjectArray<mirror::DexCache>());
-  }
-  return dex_caches_vector;
-}
-
-void ClassLinker::AddBootImageClassesToClassTable() {
-  if (dex_cache_boot_image_class_lookup_required_) {
-    AddImageClassesToClassTable(Runtime::Current()->GetHeap()->GetBootImageSpaces(),
-                                /*class_loader*/nullptr);
-    dex_cache_boot_image_class_lookup_required_ = false;
-  }
-}
-
-void ClassLinker::AddImageClassesToClassTable(std::vector<gc::space::ImageSpace*> image_spaces,
-                                              mirror::ClassLoader* class_loader) {
-  Thread* self = Thread::Current();
-  WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
-  ScopedAssertNoThreadSuspension ants("Moving image classes to class table");
-
-  ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
-
-  std::string temp;
-  std::vector<mirror::ObjectArray<mirror::DexCache>*> dex_caches_vector =
-      GetImageDexCaches(image_spaces);
-  for (mirror::ObjectArray<mirror::DexCache>* dex_caches : dex_caches_vector) {
-    for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
-      mirror::DexCache* dex_cache = dex_caches->Get(i);
-      GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
-      for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) {
-        mirror::Class* klass = types[j].Read();
-        if (klass != nullptr) {
-          DCHECK_EQ(klass->GetClassLoader(), class_loader);
-          const char* descriptor = klass->GetDescriptor(&temp);
-          size_t hash = ComputeModifiedUtf8Hash(descriptor);
-          mirror::Class* existing = class_table->Lookup(descriptor, hash);
-          if (existing != nullptr) {
-            CHECK_EQ(existing, klass) << PrettyClassAndClassLoader(existing) << " != "
-                << PrettyClassAndClassLoader(klass);
-          } else {
-            class_table->Insert(klass);
-            if (log_new_class_table_roots_) {
-              new_class_roots_.push_back(GcRoot<mirror::Class>(klass));
-            }
-          }
-        }
-      }
-    }
-  }
+  return nullptr;
 }
 
 class MoveClassTableToPreZygoteVisitor : public ClassLoaderVisitor {
@@ -3765,28 +3607,6 @@
   VisitClassLoaders(&visitor);
 }
 
-mirror::Class* ClassLinker::LookupClassFromBootImage(const char* descriptor) {
-  ScopedAssertNoThreadSuspension ants("Image class lookup");
-  std::vector<mirror::ObjectArray<mirror::DexCache>*> dex_caches_vector =
-      GetImageDexCaches(Runtime::Current()->GetHeap()->GetBootImageSpaces());
-  for (mirror::ObjectArray<mirror::DexCache>* dex_caches : dex_caches_vector) {
-    for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
-      mirror::DexCache* dex_cache = dex_caches->Get(i);
-      const DexFile* dex_file = dex_cache->GetDexFile();
-      // Try binary searching the type index by descriptor.
-      const DexFile::TypeId* type_id = dex_file->FindTypeId(descriptor);
-      if (type_id != nullptr) {
-        uint16_t type_idx = dex_file->GetIndexForTypeId(*type_id);
-        mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
-        if (klass != nullptr) {
-          return klass;
-        }
-      }
-    }
-  }
-  return nullptr;
-}
-
 // Look up classes by hash and descriptor and put all matching ones in the result array.
 class LookupClassesVisitor : public ClassLoaderVisitor {
  public:
@@ -3812,9 +3632,6 @@
 
 void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& result) {
   result.clear();
-  if (dex_cache_boot_image_class_lookup_required_) {
-    AddBootImageClassesToClassTable();
-  }
   Thread* const self = Thread::Current();
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
   const size_t hash = ComputeModifiedUtf8Hash(descriptor);
@@ -5217,14 +5034,6 @@
         Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
       }
       CHECK_EQ(existing, klass.Get());
-      if (kIsDebugBuild && class_loader == nullptr && dex_cache_boot_image_class_lookup_required_) {
-        // Check a class loaded with the system class loader matches one in the image if the class
-        // is in the image.
-        mirror::Class* const image_class = LookupClassFromBootImage(descriptor);
-        if (image_class != nullptr) {
-          CHECK_EQ(klass.Get(), existing) << descriptor;
-        }
-      }
       if (log_new_class_table_roots_) {
         new_class_roots_.push_back(GcRoot<mirror::Class>(h_new_class.Get()));
       }
@@ -8093,9 +7902,6 @@
 
 void ClassLinker::DumpForSigQuit(std::ostream& os) {
   ScopedObjectAccess soa(Thread::Current());
-  if (dex_cache_boot_image_class_lookup_required_) {
-    AddBootImageClassesToClassTable();
-  }
   ReaderMutexLock mu(soa.Self(), *Locks::classlinker_classes_lock_);
   os << "Zygote loaded classes=" << NumZygoteClasses() << " post zygote classes="
      << NumNonZygoteClasses() << "\n";
@@ -8131,9 +7937,6 @@
 }
 
 size_t ClassLinker::NumLoadedClasses() {
-  if (dex_cache_boot_image_class_lookup_required_) {
-    AddBootImageClassesToClassTable();
-  }
   ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   // Only return non zygote classes since these are the ones which apps which care about.
   return NumNonZygoteClasses();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 43ffc8e..70cc768 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -561,17 +561,6 @@
     return class_roots;
   }
 
-  // Move all of the boot image classes into the class table for faster lookups.
-  void AddBootImageClassesToClassTable()
-      REQUIRES(!Locks::classlinker_classes_lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Add image classes to the class table.
-  void AddImageClassesToClassTable(std::vector<gc::space::ImageSpace*> image_spaces,
-                                   mirror::ClassLoader* class_loader)
-      REQUIRES(!Locks::classlinker_classes_lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Move the class table to the pre-zygote table to reduce memory usage. This works by ensuring
   // that no more classes are ever added to the pre zygote table which makes it that the pages
   // always remain shared dirty instead of private dirty.
@@ -1050,9 +1039,6 @@
   void EnsureSkipAccessChecksMethods(Handle<mirror::Class> c)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  mirror::Class* LookupClassFromBootImage(const char* descriptor)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Register a class loader and create its class table and allocator. Should not be called if
   // these are already created.
   void RegisterClassLoader(mirror::ClassLoader* class_loader)
@@ -1157,8 +1143,6 @@
   // New class roots, only used by CMS since the GC needs to mark these in the pause.
   std::vector<GcRoot<mirror::Class>> new_class_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
 
-  // Do we need to search dex caches to find boot image classes?
-  bool dex_cache_boot_image_class_lookup_required_;
   // Number of times we've searched dex caches for a class. After a certain number of misses we move
   // the classes into the class_table_ to avoid dex cache based searches.
   Atomic<uint32_t> failed_dex_cache_class_lookups_;
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 096f003..2ea7bb6 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -36,8 +36,7 @@
 ElfFileImpl<ElfTypes>::ElfFileImpl(File* file, bool writable,
                                    bool program_header_only,
                                    uint8_t* requested_base)
-  : file_(file),
-    writable_(writable),
+  : writable_(writable),
     program_header_only_(program_header_only),
     header_(nullptr),
     base_address_(nullptr),
@@ -74,7 +73,7 @@
     prot = PROT_READ;
     flags = MAP_PRIVATE;
   }
-  if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) {
+  if (!elf_file->Setup(file, prot, flags, low_4gb, error_msg)) {
     return nullptr;
   }
   return elf_file.release();
@@ -89,39 +88,44 @@
   std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes>
       (file, (prot & PROT_WRITE) == PROT_WRITE, /*program_header_only*/false,
       /*requested_base*/nullptr));
-  if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) {
+  if (!elf_file->Setup(file, prot, flags, low_4gb, error_msg)) {
     return nullptr;
   }
   return elf_file.release();
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, bool low_4gb, std::string* error_msg) {
-  int64_t temp_file_length = file_->GetLength();
+bool ElfFileImpl<ElfTypes>::Setup(File* file,
+                                  int prot,
+                                  int flags,
+                                  bool low_4gb,
+                                  std::string* error_msg) {
+  int64_t temp_file_length = file->GetLength();
   if (temp_file_length < 0) {
     errno = -temp_file_length;
     *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s",
-                              file_->GetPath().c_str(), file_->Fd(), strerror(errno));
+                              file->GetPath().c_str(), file->Fd(), strerror(errno));
     return false;
   }
   size_t file_length = static_cast<size_t>(temp_file_length);
   if (file_length < sizeof(Elf_Ehdr)) {
     *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF header of "
                               "%zd bytes: '%s'", file_length, sizeof(Elf_Ehdr),
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
   if (program_header_only_) {
     // first just map ELF header to get program header size information
     size_t elf_header_size = sizeof(Elf_Ehdr);
-    if (!SetMap(MemMap::MapFile(elf_header_size,
+    if (!SetMap(file,
+                MemMap::MapFile(elf_header_size,
                                 prot,
                                 flags,
-                                file_->Fd(),
+                                file->Fd(),
                                 0,
                                 low_4gb,
-                                file_->GetPath().c_str(),
+                                file->GetPath().c_str(),
                                 error_msg),
                 error_msg)) {
       return false;
@@ -131,16 +135,17 @@
     if (file_length < program_header_size) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF program "
                                 "header of %zd bytes: '%s'", file_length,
-                                sizeof(Elf_Ehdr), file_->GetPath().c_str());
+                                sizeof(Elf_Ehdr), file->GetPath().c_str());
       return false;
     }
-    if (!SetMap(MemMap::MapFile(program_header_size,
+    if (!SetMap(file,
+                MemMap::MapFile(program_header_size,
                                 prot,
                                 flags,
-                                file_->Fd(),
+                                file->Fd(),
                                 0,
                                 low_4gb,
-                                file_->GetPath().c_str(),
+                                file->GetPath().c_str(),
                                 error_msg),
                 error_msg)) {
       *error_msg = StringPrintf("Failed to map ELF program headers: %s", error_msg->c_str());
@@ -148,13 +153,14 @@
     }
   } else {
     // otherwise map entire file
-    if (!SetMap(MemMap::MapFile(file_->GetLength(),
+    if (!SetMap(file,
+                MemMap::MapFile(file->GetLength(),
                                 prot,
                                 flags,
-                                file_->Fd(),
+                                file->Fd(),
                                 0,
                                 low_4gb,
-                                file_->GetPath().c_str(),
+                                file->GetPath().c_str(),
                                 error_msg),
                 error_msg)) {
       *error_msg = StringPrintf("Failed to map ELF file: %s", error_msg->c_str());
@@ -178,7 +184,7 @@
     Elf_Shdr* shstrtab_section_header = GetSectionNameStringSection();
     if (shstrtab_section_header == nullptr) {
       *error_msg = StringPrintf("Failed to find shstrtab section header in ELF file: '%s'",
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
 
@@ -186,7 +192,7 @@
     dynamic_program_header_ = FindProgamHeaderByType(PT_DYNAMIC);
     if (dynamic_program_header_ == nullptr) {
       *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
 
@@ -200,7 +206,7 @@
       Elf_Shdr* section_header = GetSectionHeader(i);
       if (section_header == nullptr) {
         *error_msg = StringPrintf("Failed to find section header for section %d in ELF file: '%s'",
-                                  i, file_->GetPath().c_str());
+                                  i, file->GetPath().c_str());
         return false;
       }
       switch (section_header->sh_type) {
@@ -245,7 +251,7 @@
           if (reinterpret_cast<uint8_t*>(dynamic_section_start_) !=
               Begin() + section_header->sh_offset) {
             LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in "
-                         << file_->GetPath() << ": " << std::hex
+                         << file->GetPath() << ": " << std::hex
                          << reinterpret_cast<void*>(dynamic_section_start_)
                          << " != " << reinterpret_cast<void*>(Begin() + section_header->sh_offset);
             return false;
@@ -263,7 +269,7 @@
     }
 
     // Check for the existence of some sections.
-    if (!CheckSectionsExist(error_msg)) {
+    if (!CheckSectionsExist(file, error_msg)) {
       return false;
     }
   }
@@ -283,7 +289,7 @@
                                         uint8_t** target, std::string* error_msg) {
   if (Begin() + offset >= End()) {
     *error_msg = StringPrintf("Offset %d is out of range for %s in ELF file: '%s'", offset, label,
-                              file_->GetPath().c_str());
+                              file_path_.c_str());
     return false;
   }
   *target = Begin() + offset;
@@ -324,11 +330,11 @@
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::CheckSectionsExist(std::string* error_msg) const {
+  bool ElfFileImpl<ElfTypes>::CheckSectionsExist(File* file, std::string* error_msg) const {
   if (!program_header_only_) {
     // If in full mode, need section headers.
     if (section_headers_start_ == nullptr) {
-      *error_msg = StringPrintf("No section headers in ELF file: '%s'", file_->GetPath().c_str());
+      *error_msg = StringPrintf("No section headers in ELF file: '%s'", file->GetPath().c_str());
       return false;
     }
   }
@@ -336,14 +342,14 @@
   // This is redundant, but defensive.
   if (dynamic_program_header_ == nullptr) {
     *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
   // Need a dynamic section. This is redundant, but defensive.
   if (dynamic_section_start_ == nullptr) {
     *error_msg = StringPrintf("Failed to find dynamic section in ELF file: '%s'",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
@@ -352,7 +358,7 @@
   if (symtab_section_start_ != nullptr) {
     // When there's a symtab, there should be a strtab.
     if (strtab_section_start_ == nullptr) {
-      *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file_->GetPath().c_str());
+      *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file->GetPath().c_str());
       return false;
     }
 
@@ -360,25 +366,25 @@
     if (!CheckSectionsLinked(reinterpret_cast<const uint8_t*>(symtab_section_start_),
                              reinterpret_cast<const uint8_t*>(strtab_section_start_))) {
       *error_msg = StringPrintf("Symtab is not linked to the strtab in ELF file: '%s'",
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
   }
 
   // We always need a dynstr & dynsym.
   if (dynstr_section_start_ == nullptr) {
-    *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file_->GetPath().c_str());
+    *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file->GetPath().c_str());
     return false;
   }
   if (dynsym_section_start_ == nullptr) {
-    *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file_->GetPath().c_str());
+    *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file->GetPath().c_str());
     return false;
   }
 
   // Need a hash section for dynamic symbol lookup.
   if (hash_section_start_ == nullptr) {
     *error_msg = StringPrintf("Failed to find hash section in ELF file: '%s'",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
@@ -386,7 +392,7 @@
   if (!CheckSectionsLinked(reinterpret_cast<const uint8_t*>(hash_section_start_),
                            reinterpret_cast<const uint8_t*>(dynsym_section_start_))) {
     *error_msg = StringPrintf("Hash section is not linked to the dynstr in ELF file: '%s'",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
@@ -397,9 +403,9 @@
     // It might not be mapped, but we can compare against the file size.
     int64_t offset = static_cast<int64_t>(GetHeader().e_shoff +
                                           (GetHeader().e_shstrndx * GetHeader().e_shentsize));
-    if (offset >= file_->GetLength()) {
+    if (offset >= file->GetLength()) {
       *error_msg = StringPrintf("Shstrtab is not in the mapped ELF file: '%s'",
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
   }
@@ -408,15 +414,15 @@
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::SetMap(MemMap* map, std::string* error_msg) {
+bool ElfFileImpl<ElfTypes>::SetMap(File* file, MemMap* map, std::string* error_msg) {
   if (map == nullptr) {
     // MemMap::Open should have already set an error.
     DCHECK(!error_msg->empty());
     return false;
   }
   map_.reset(map);
-  CHECK(map_.get() != nullptr) << file_->GetPath();
-  CHECK(map_->Begin() != nullptr) << file_->GetPath();
+  CHECK(map_.get() != nullptr) << file->GetPath();
+  CHECK(map_->Begin() != nullptr) << file->GetPath();
 
   header_ = reinterpret_cast<Elf_Ehdr*>(map_->Begin());
   if ((ELFMAG0 != header_->e_ident[EI_MAG0])
@@ -425,7 +431,7 @@
       || (ELFMAG3 != header_->e_ident[EI_MAG3])) {
     *error_msg = StringPrintf("Failed to find ELF magic value %d %d %d %d in %s, found %d %d %d %d",
                               ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_ident[EI_MAG0],
                               header_->e_ident[EI_MAG1],
                               header_->e_ident[EI_MAG2],
@@ -436,90 +442,90 @@
   if (elf_class != header_->e_ident[EI_CLASS]) {
     *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d",
                               elf_class,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_ident[EI_CLASS]);
     return false;
   }
   if (ELFDATA2LSB != header_->e_ident[EI_DATA]) {
     *error_msg = StringPrintf("Failed to find expected EI_DATA value %d in %s, found %d",
                               ELFDATA2LSB,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_ident[EI_CLASS]);
     return false;
   }
   if (EV_CURRENT != header_->e_ident[EI_VERSION]) {
     *error_msg = StringPrintf("Failed to find expected EI_VERSION value %d in %s, found %d",
                               EV_CURRENT,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_ident[EI_CLASS]);
     return false;
   }
   if (ET_DYN != header_->e_type) {
     *error_msg = StringPrintf("Failed to find expected e_type value %d in %s, found %d",
                               ET_DYN,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_type);
     return false;
   }
   if (EV_CURRENT != header_->e_version) {
     *error_msg = StringPrintf("Failed to find expected e_version value %d in %s, found %d",
                               EV_CURRENT,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               header_->e_version);
     return false;
   }
   if (0 != header_->e_entry) {
     *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d",
                               0,
-                              file_->GetPath().c_str(),
+                              file->GetPath().c_str(),
                               static_cast<int32_t>(header_->e_entry));
     return false;
   }
   if (0 == header_->e_phoff) {
     *error_msg = StringPrintf("Failed to find non-zero e_phoff value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_shoff) {
     *error_msg = StringPrintf("Failed to find non-zero e_shoff value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_ehsize) {
     *error_msg = StringPrintf("Failed to find non-zero e_ehsize value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_phentsize) {
     *error_msg = StringPrintf("Failed to find non-zero e_phentsize value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_phnum) {
     *error_msg = StringPrintf("Failed to find non-zero e_phnum value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_shentsize) {
     *error_msg = StringPrintf("Failed to find non-zero e_shentsize value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_shnum) {
     *error_msg = StringPrintf("Failed to find non-zero e_shnum value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (0 == header_->e_shstrndx) {
     *error_msg = StringPrintf("Failed to find non-zero e_shstrndx value in %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   if (header_->e_shstrndx >= header_->e_shnum) {
     *error_msg = StringPrintf("Failed to find e_shnum value %d less than %d in %s",
                               header_->e_shstrndx,
                               header_->e_shnum,
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
 
@@ -528,14 +534,14 @@
       *error_msg = StringPrintf("Failed to find e_phoff value %" PRIu64 " less than %zd in %s",
                                 static_cast<uint64_t>(header_->e_phoff),
                                 Size(),
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
     if (header_->e_shoff >= Size()) {
       *error_msg = StringPrintf("Failed to find e_shoff value %" PRIu64 " less than %zd in %s",
                                 static_cast<uint64_t>(header_->e_shoff),
                                 Size(),
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
   }
@@ -577,7 +583,7 @@
 template <typename ElfTypes>
 typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::GetSymbolSectionStart(
     Elf_Word section_type) const {
-  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
       return symtab_section_start_;
@@ -597,7 +603,7 @@
 template <typename ElfTypes>
 const char* ElfFileImpl<ElfTypes>::GetStringSectionStart(
     Elf_Word section_type) const {
-  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
       return strtab_section_start_;
@@ -615,7 +621,7 @@
 template <typename ElfTypes>
 const char* ElfFileImpl<ElfTypes>::GetString(Elf_Word section_type,
                                              Elf_Word i) const {
-  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type;
   if (i == 0) {
     return nullptr;
   }
@@ -673,7 +679,7 @@
 
 template <typename ElfTypes>
 typename ElfTypes::Phdr* ElfFileImpl<ElfTypes>::GetProgramHeader(Elf_Word i) const {
-  CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath();  // Sanity check for caller.
+  CHECK_LT(i, GetProgramHeaderNum()) << file_path_;  // Sanity check for caller.
   uint8_t* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
   if (program_header >= End()) {
     return nullptr;  // Failure condition.
@@ -701,7 +707,7 @@
 typename ElfTypes::Shdr* ElfFileImpl<ElfTypes>::GetSectionHeader(Elf_Word i) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // Even if we Load(), it doesn't bring in all the sections.
-  CHECK(!program_header_only_) << file_->GetPath();
+  CHECK(!program_header_only_) << file_path_;
   if (i >= GetSectionHeaderNum()) {
     return nullptr;  // Failure condition.
   }
@@ -716,7 +722,7 @@
 typename ElfTypes::Shdr* ElfFileImpl<ElfTypes>::FindSectionByType(Elf_Word type) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // We could change this to switch on known types if they were detected during loading.
-  CHECK(!program_header_only_) << file_->GetPath();
+  CHECK(!program_header_only_) << file_path_;
   for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
     Elf_Shdr* section_header = GetSectionHeader(i);
     if (section_header->sh_type == type) {
@@ -802,8 +808,8 @@
 template <typename ElfTypes>
 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetSymbolNum(Elf_Shdr& section_header) const {
   CHECK(IsSymbolSectionType(section_header.sh_type))
-      << file_->GetPath() << " " << section_header.sh_type;
-  CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
+      << file_path_ << " " << section_header.sh_type;
+  CHECK_NE(0U, section_header.sh_entsize) << file_path_;
   return section_header.sh_size / section_header.sh_entsize;
 }
 
@@ -819,7 +825,7 @@
 template <typename ElfTypes>
 typename ElfFileImpl<ElfTypes>::SymbolTable**
 ElfFileImpl<ElfTypes>::GetSymbolTable(Elf_Word section_type) {
-  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
       return &symtab_symbol_table_;
@@ -837,8 +843,8 @@
 template <typename ElfTypes>
 typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::FindSymbolByName(
     Elf_Word section_type, const std::string& symbol_name, bool build_map) {
-  CHECK(!program_header_only_) << file_->GetPath();
-  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  CHECK(!program_header_only_) << file_path_;
+  CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type;
 
   SymbolTable** symbol_table = GetSymbolTable(section_type);
   if (*symbol_table != nullptr || build_map) {
@@ -928,7 +934,7 @@
 template <typename ElfTypes>
 const char* ElfFileImpl<ElfTypes>::GetString(Elf_Shdr& string_section,
                                              Elf_Word i) const {
-  CHECK(!program_header_only_) << file_->GetPath();
+  CHECK(!program_header_only_) << file_path_;
   // TODO: remove this static_cast from enum when using -std=gnu++0x
   if (static_cast<Elf_Word>(SHT_STRTAB) != string_section.sh_type) {
     return nullptr;  // Failure condition.
@@ -954,7 +960,7 @@
 
 template <typename ElfTypes>
 typename ElfTypes::Dyn& ElfFileImpl<ElfTypes>::GetDynamic(Elf_Word i) const {
-  CHECK_LT(i, GetDynamicNum()) << file_->GetPath();
+  CHECK_LT(i, GetDynamicNum()) << file_path_;
   return *(GetDynamicSectionStart() + i);
 }
 
@@ -981,40 +987,40 @@
 
 template <typename ElfTypes>
 typename ElfTypes::Rel* ElfFileImpl<ElfTypes>::GetRelSectionStart(Elf_Shdr& section_header) const {
-  CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK(SHT_REL == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
   return reinterpret_cast<Elf_Rel*>(Begin() + section_header.sh_offset);
 }
 
 template <typename ElfTypes>
 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetRelNum(Elf_Shdr& section_header) const {
-  CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
+  CHECK(SHT_REL == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
+  CHECK_NE(0U, section_header.sh_entsize) << file_path_;
   return section_header.sh_size / section_header.sh_entsize;
 }
 
 template <typename ElfTypes>
 typename ElfTypes::Rel& ElfFileImpl<ElfTypes>::GetRel(Elf_Shdr& section_header, Elf_Word i) const {
-  CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath();
+  CHECK(SHT_REL == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
+  CHECK_LT(i, GetRelNum(section_header)) << file_path_;
   return *(GetRelSectionStart(section_header) + i);
 }
 
 template <typename ElfTypes>
 typename ElfTypes::Rela* ElfFileImpl<ElfTypes>::GetRelaSectionStart(Elf_Shdr& section_header) const {
-  CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK(SHT_RELA == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
   return reinterpret_cast<Elf_Rela*>(Begin() + section_header.sh_offset);
 }
 
 template <typename ElfTypes>
 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetRelaNum(Elf_Shdr& section_header) const {
-  CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK(SHT_RELA == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
   return section_header.sh_size / section_header.sh_entsize;
 }
 
 template <typename ElfTypes>
 typename ElfTypes::Rela& ElfFileImpl<ElfTypes>::GetRela(Elf_Shdr& section_header, Elf_Word i) const {
-  CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath();
+  CHECK(SHT_RELA == section_header.sh_type) << file_path_ << " " << section_header.sh_type;
+  CHECK_LT(i, GetRelaNum(section_header)) << file_path_;
   return *(GetRelaSectionStart(section_header) + i);
 }
 
@@ -1037,7 +1043,7 @@
       std::ostringstream oss;
       oss << "Program header #" << i << " has overflow in p_vaddr+p_memsz: 0x" << std::hex
           << program_header->p_vaddr << "+0x" << program_header->p_memsz << "=0x" << end_vaddr
-          << " in ELF file \"" << file_->GetPath() << "\"";
+          << " in ELF file \"" << file_path_ << "\"";
       *error_msg = oss.str();
       *size = static_cast<size_t>(-1);
       return false;
@@ -1048,13 +1054,13 @@
   }
   min_vaddr = RoundDown(min_vaddr, kPageSize);
   max_vaddr = RoundUp(max_vaddr, kPageSize);
-  CHECK_LT(min_vaddr, max_vaddr) << file_->GetPath();
+  CHECK_LT(min_vaddr, max_vaddr) << file_path_;
   Elf_Addr loaded_size = max_vaddr - min_vaddr;
   // Check that the loaded_size fits in size_t.
   if (UNLIKELY(loaded_size > std::numeric_limits<size_t>::max())) {
     std::ostringstream oss;
     oss << "Loaded size is 0x" << std::hex << loaded_size << " but maximum size_t is 0x"
-        << std::numeric_limits<size_t>::max() << " for ELF file \"" << file_->GetPath() << "\"";
+        << std::numeric_limits<size_t>::max() << " for ELF file \"" << file_path_ << "\"";
     *error_msg = oss.str();
     *size = static_cast<size_t>(-1);
     return false;
@@ -1064,8 +1070,11 @@
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::Load(bool executable, bool low_4gb, std::string* error_msg) {
-  CHECK(program_header_only_) << file_->GetPath();
+bool ElfFileImpl<ElfTypes>::Load(File* file,
+                                 bool executable,
+                                 bool low_4gb,
+                                 std::string* error_msg) {
+  CHECK(program_header_only_) << file->GetPath();
 
   if (executable) {
     InstructionSet elf_ISA = GetInstructionSetFromELF(GetHeader().e_machine, GetHeader().e_flags);
@@ -1082,7 +1091,7 @@
     Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header == nullptr) {
       *error_msg = StringPrintf("No program header for entry %d in ELF file %s.",
-                                i, file_->GetPath().c_str());
+                                i, file->GetPath().c_str());
       return false;
     }
 
@@ -1106,11 +1115,11 @@
     // non-zero, the segments require the specific address specified,
     // which either was specified in the file because we already set
     // base_address_ after the first zero segment).
-    int64_t temp_file_length = file_->GetLength();
+    int64_t temp_file_length = file->GetLength();
     if (temp_file_length < 0) {
       errno = -temp_file_length;
       *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s",
-                                file_->GetPath().c_str(), file_->Fd(), strerror(errno));
+                                file->GetPath().c_str(), file->Fd(), strerror(errno));
       return false;
     }
     size_t file_length = static_cast<size_t>(temp_file_length);
@@ -1122,7 +1131,7 @@
         reserve_base_override = requested_base_;
       }
       std::string reservation_name("ElfFile reservation for ");
-      reservation_name += file_->GetPath();
+      reservation_name += file->GetPath();
       size_t loaded_size;
       if (!GetLoadedSize(&loaded_size, error_msg)) {
         DCHECK(!error_msg->empty());
@@ -1178,7 +1187,7 @@
       *error_msg = StringPrintf("Invalid p_filesz > p_memsz (%" PRIu64 " > %" PRIu64 "): %s",
                                 static_cast<uint64_t>(program_header->p_filesz),
                                 static_cast<uint64_t>(program_header->p_memsz),
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
     if (program_header->p_filesz < program_header->p_memsz &&
@@ -1187,14 +1196,14 @@
                                 " < %" PRIu64 "): %s",
                                 static_cast<uint64_t>(program_header->p_filesz),
                                 static_cast<uint64_t>(program_header->p_memsz),
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
     if (file_length < (program_header->p_offset + program_header->p_filesz)) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment "
                                 "%d of %" PRIu64 " bytes: '%s'", file_length, i,
                                 static_cast<uint64_t>(program_header->p_offset + program_header->p_filesz),
-                                file_->GetPath().c_str());
+                                file->GetPath().c_str());
       return false;
     }
     if (program_header->p_filesz != 0u) {
@@ -1203,28 +1212,28 @@
                                    program_header->p_filesz,
                                    prot,
                                    flags,
-                                   file_->Fd(),
+                                   file->Fd(),
                                    program_header->p_offset,
                                    /*low4_gb*/false,
                                    /*reuse*/true,  // implies MAP_FIXED
-                                   file_->GetPath().c_str(),
+                                   file->GetPath().c_str(),
                                    error_msg));
       if (segment.get() == nullptr) {
         *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s",
-                                  i, file_->GetPath().c_str(), error_msg->c_str());
+                                  i, file->GetPath().c_str(), error_msg->c_str());
         return false;
       }
       if (segment->Begin() != p_vaddr) {
         *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, "
                                   "instead mapped to %p",
-                                  i, file_->GetPath().c_str(), p_vaddr, segment->Begin());
+                                  i, file->GetPath().c_str(), p_vaddr, segment->Begin());
         return false;
       }
       segments_.push_back(segment.release());
     }
     if (program_header->p_filesz < program_header->p_memsz) {
       std::string name = StringPrintf("Zero-initialized segment %" PRIu64 " of ELF file %s",
-                                      static_cast<uint64_t>(i), file_->GetPath().c_str());
+                                      static_cast<uint64_t>(i), file->GetPath().c_str());
       std::unique_ptr<MemMap> segment(
           MemMap::MapAnonymous(name.c_str(),
                                p_vaddr + program_header->p_filesz,
@@ -1232,13 +1241,13 @@
                                prot, false, true /* reuse */, error_msg));
       if (segment == nullptr) {
         *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s: %s",
-                                  i, file_->GetPath().c_str(), error_msg->c_str());
+                                  i, file->GetPath().c_str(), error_msg->c_str());
         return false;
       }
       if (segment->Begin() != p_vaddr) {
         *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s "
                                   "at expected address %p, instead mapped to %p",
-                                  i, file_->GetPath().c_str(), p_vaddr, segment->Begin());
+                                  i, file->GetPath().c_str(), p_vaddr, segment->Begin());
         return false;
       }
       segments_.push_back(segment.release());
@@ -1249,7 +1258,7 @@
   uint8_t* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr;
   if ((dsptr < Begin() || dsptr >= End()) && !ValidPointer(dsptr)) {
     *error_msg = StringPrintf("dynamic section address invalid in ELF file %s",
-                              file_->GetPath().c_str());
+                              file->GetPath().c_str());
     return false;
   }
   dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr);
@@ -1261,7 +1270,7 @@
       case DT_HASH: {
         if (!ValidPointer(d_ptr)) {
           *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
-                                    d_ptr, file_->GetPath().c_str());
+                                    d_ptr, file->GetPath().c_str());
           return false;
         }
         hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr);
@@ -1270,7 +1279,7 @@
       case DT_STRTAB: {
         if (!ValidPointer(d_ptr)) {
           *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
-                                    d_ptr, file_->GetPath().c_str());
+                                    d_ptr, file->GetPath().c_str());
           return false;
         }
         dynstr_section_start_ = reinterpret_cast<char*>(d_ptr);
@@ -1279,7 +1288,7 @@
       case DT_SYMTAB: {
         if (!ValidPointer(d_ptr)) {
           *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
-                                    d_ptr, file_->GetPath().c_str());
+                                    d_ptr, file->GetPath().c_str());
           return false;
         }
         dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr);
@@ -1289,7 +1298,7 @@
         if (GetDynamicNum() != i+1) {
           *error_msg = StringPrintf("DT_NULL found after %d .dynamic entries, "
                                     "expected %d as implied by size of PT_DYNAMIC segment in %s",
-                                    i + 1, GetDynamicNum(), file_->GetPath().c_str());
+                                    i + 1, GetDynamicNum(), file->GetPath().c_str());
           return false;
         }
         break;
@@ -1298,7 +1307,7 @@
   }
 
   // Check for the existence of some sections.
-  if (!CheckSectionsExist(error_msg)) {
+  if (!CheckSectionsExist(file, error_msg)) {
     return false;
   }
 
@@ -1392,7 +1401,7 @@
 }
 
 template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::Strip(std::string* error_msg) {
+bool ElfFileImpl<ElfTypes>::Strip(File* file, std::string* error_msg) {
   // ELF files produced by MCLinker look roughly like this
   //
   // +------------+
@@ -1484,10 +1493,10 @@
 
   GetHeader().e_shnum = section_headers.size();
   GetHeader().e_shoff = shoff;
-  int result = ftruncate(file_->Fd(), offset);
+  int result = ftruncate(file->Fd(), offset);
   if (result != 0) {
     *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
-                              file_->GetPath().c_str(), strerror(errno));
+                              file->GetPath().c_str(), strerror(errno));
     return false;
   }
   return true;
@@ -1498,32 +1507,32 @@
 template <typename ElfTypes>
 bool ElfFileImpl<ElfTypes>::Fixup(Elf_Addr base_address) {
   if (!FixupDynamic(base_address)) {
-    LOG(WARNING) << "Failed to fixup .dynamic in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup .dynamic in " << file_path_;
     return false;
   }
   if (!FixupSectionHeaders(base_address)) {
-    LOG(WARNING) << "Failed to fixup section headers in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup section headers in " << file_path_;
     return false;
   }
   if (!FixupProgramHeaders(base_address)) {
-    LOG(WARNING) << "Failed to fixup program headers in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup program headers in " << file_path_;
     return false;
   }
   if (!FixupSymbols(base_address, true)) {
-    LOG(WARNING) << "Failed to fixup .dynsym in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup .dynsym in " << file_path_;
     return false;
   }
   if (!FixupSymbols(base_address, false)) {
-    LOG(WARNING) << "Failed to fixup .symtab in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup .symtab in " << file_path_;
     return false;
   }
   if (!FixupRelocations(base_address)) {
-    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_path_;
     return false;
   }
   static_assert(sizeof(Elf_Off) >= sizeof(base_address), "Potentially losing precision.");
   if (!FixupDebugSections(static_cast<Elf_Off>(base_address))) {
-    LOG(WARNING) << "Failed to fixup debug sections in " << file_->GetPath();
+    LOG(WARNING) << "Failed to fixup debug sections in " << file_path_;
     return false;
   }
   return true;
@@ -1538,7 +1547,7 @@
       Elf_Addr d_ptr = elf_dyn.d_un.d_ptr;
       if (DEBUG_FIXUP) {
         LOG(INFO) << StringPrintf("In %s moving Elf_Dyn[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                  GetFile().GetPath().c_str(), i,
+                                  file_path_.c_str(), i,
                                   static_cast<uint64_t>(d_ptr),
                                   static_cast<uint64_t>(d_ptr + base_address));
       }
@@ -1560,7 +1569,7 @@
     }
     if (DEBUG_FIXUP) {
       LOG(INFO) << StringPrintf("In %s moving Elf_Shdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                GetFile().GetPath().c_str(), i,
+                                file_path_.c_str(), i,
                                 static_cast<uint64_t>(sh->sh_addr),
                                 static_cast<uint64_t>(sh->sh_addr + base_address));
     }
@@ -1575,19 +1584,19 @@
   for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
     Elf_Phdr* ph = GetProgramHeader(i);
     CHECK(ph != nullptr);
-    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << GetFile().GetPath() << " i=" << i;
+    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << file_path_ << " i=" << i;
     CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << GetFile().GetPath() << " i=" << i;
+        << file_path_ << " i=" << i;
     if (DEBUG_FIXUP) {
       LOG(INFO) << StringPrintf("In %s moving Elf_Phdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                GetFile().GetPath().c_str(), i,
+                                file_path_.c_str(), i,
                                 static_cast<uint64_t>(ph->p_vaddr),
                                 static_cast<uint64_t>(ph->p_vaddr + base_address));
     }
     ph->p_vaddr += base_address;
     ph->p_paddr += base_address;
     CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << GetFile().GetPath() << " i=" << i;
+        << file_path_ << " i=" << i;
   }
   return true;
 }
@@ -1599,7 +1608,7 @@
   Elf_Shdr* symbol_section = FindSectionByType(section_type);
   if (symbol_section == nullptr) {
     // file is missing optional .symtab
-    CHECK(!dynamic) << GetFile().GetPath();
+    CHECK(!dynamic) << file_path_;
     return true;
   }
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
@@ -1608,7 +1617,7 @@
     if (symbol->st_value != 0) {
       if (DEBUG_FIXUP) {
         LOG(INFO) << StringPrintf("In %s moving Elf_Sym[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                  GetFile().GetPath().c_str(), i,
+                                  file_path_.c_str(), i,
                                   static_cast<uint64_t>(symbol->st_value),
                                   static_cast<uint64_t>(symbol->st_value + base_address));
       }
@@ -1628,7 +1637,7 @@
         Elf_Rel& rel = GetRel(*sh, j);
         if (DEBUG_FIXUP) {
           LOG(INFO) << StringPrintf("In %s moving Elf_Rel[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                    GetFile().GetPath().c_str(), j,
+                                    file_path_.c_str(), j,
                                     static_cast<uint64_t>(rel.r_offset),
                                     static_cast<uint64_t>(rel.r_offset + base_address));
         }
@@ -1639,7 +1648,7 @@
         Elf_Rela& rela = GetRela(*sh, j);
         if (DEBUG_FIXUP) {
           LOG(INFO) << StringPrintf("In %s moving Elf_Rela[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
-                                    GetFile().GetPath().c_str(), j,
+                                    file_path_.c_str(), j,
                                     static_cast<uint64_t>(rela.r_offset),
                                     static_cast<uint64_t>(rela.r_offset + base_address));
         }
@@ -1695,8 +1704,9 @@
                                                        low_4gb,
                                                        error_msg,
                                                        requested_base);
-    if (elf_file_impl == nullptr)
+    if (elf_file_impl == nullptr) {
       return nullptr;
+    }
     return new ElfFile(elf_file_impl);
   } else if (header[EI_CLASS] == ELFCLASS32) {
     ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file,
@@ -1775,8 +1785,8 @@
     return elf32_->func(__VA_ARGS__); \
   }
 
-bool ElfFile::Load(bool executable, bool low_4gb, std::string* error_msg) {
-  DELEGATE_TO_IMPL(Load, executable, low_4gb, error_msg);
+bool ElfFile::Load(File* file, bool executable, bool low_4gb, std::string* error_msg) {
+  DELEGATE_TO_IMPL(Load, file, executable, low_4gb, error_msg);
 }
 
 const uint8_t* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
@@ -1795,8 +1805,8 @@
   DELEGATE_TO_IMPL(End);
 }
 
-const File& ElfFile::GetFile() const {
-  DELEGATE_TO_IMPL(GetFile);
+const std::string& ElfFile::GetFilePath() const {
+  DELEGATE_TO_IMPL(GetFilePath);
 }
 
 bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset,
@@ -1854,10 +1864,11 @@
     return false;
   }
 
-  if (elf_file->elf64_.get() != nullptr)
-    return elf_file->elf64_->Strip(error_msg);
-  else
-    return elf_file->elf32_->Strip(error_msg);
+  if (elf_file->elf64_.get() != nullptr) {
+    return elf_file->elf64_->Strip(file, error_msg);
+  } else {
+    return elf_file->elf32_->Strip(file, error_msg);
+  }
 }
 
 bool ElfFile::Fixup(uint64_t base_address) {
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index c3616f7..b1c9395 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -53,7 +53,7 @@
   ~ElfFile();
 
   // Load segments into memory based on PT_LOAD program headers
-  bool Load(bool executable, bool low_4gb, std::string* error_msg);
+  bool Load(File* file, bool executable, bool low_4gb, std::string* error_msg);
 
   const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const;
 
@@ -65,7 +65,7 @@
   // The end of the memory map address range for this ELF file.
   uint8_t* End() const;
 
-  const File& GetFile() const;
+  const std::string& GetFilePath() const;
 
   bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) const;
 
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index 1cdbedc..04c2243 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -61,8 +61,8 @@
                            std::string* error_msg);
   ~ElfFileImpl();
 
-  const File& GetFile() const {
-    return *file_;
+  const std::string& GetFilePath() const {
+    return file_path_;
   }
 
   uint8_t* Begin() const {
@@ -119,7 +119,7 @@
 
   // Load segments into memory based on PT_LOAD program headers.
   // executable is true at run time, false at compile time.
-  bool Load(bool executable, bool low_4gb, std::string* error_msg);
+  bool Load(File* file, bool executable, bool low_4gb, std::string* error_msg);
 
   bool Fixup(Elf_Addr base_address);
   bool FixupDynamic(Elf_Addr base_address);
@@ -132,14 +132,14 @@
   static void ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta,
                               uint8_t* to_patch, const uint8_t* to_patch_end);
 
-  bool Strip(std::string* error_msg);
+  bool Strip(File* file, std::string* error_msg);
 
  private:
   ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base);
 
-  bool Setup(int prot, int flags, bool low_4gb, std::string* error_msg);
+  bool Setup(File* file, int prot, int flags, bool low_4gb, std::string* error_msg);
 
-  bool SetMap(MemMap* map, std::string* error_msg);
+  bool SetMap(File* file, MemMap* map, std::string* error_msg);
 
   uint8_t* GetProgramHeadersStart() const;
   uint8_t* GetSectionHeadersStart() const;
@@ -163,7 +163,7 @@
   const Elf_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
 
   // Check that certain sections and their dependencies exist.
-  bool CheckSectionsExist(std::string* error_msg) const;
+  bool CheckSectionsExist(File* file, std::string* error_msg) const;
 
   // Check that the link of the first section links to the second section.
   bool CheckSectionsLinked(const uint8_t* source, const uint8_t* target) const;
@@ -191,7 +191,7 @@
   // Lookup a string by section type. Returns null for special 0 offset.
   const char* GetString(Elf_Word section_type, Elf_Word) const;
 
-  const File* const file_;
+  const std::string file_path_;
   const bool writable_;
   const bool program_header_only_;
 
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 4311d19..2a3a6bf 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -63,12 +63,14 @@
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
   mirror::String* result = ResolveStringFromCode(caller, string_idx);
   if (LIKELY(result != nullptr)) {
-    // For AOT code, we need a write barrier for the dex cache that holds the GC roots in the .bss.
+    // For AOT code, we need a write barrier for the class loader that holds
+    // the GC roots in the .bss.
     const DexFile* dex_file = caller->GetDexFile();
     if (dex_file != nullptr &&
         dex_file->GetOatDexFile() != nullptr &&
         !dex_file->GetOatDexFile()->GetOatFile()->GetBssGcRoots().empty()) {
       mirror::ClassLoader* class_loader = caller->GetDeclaringClass()->GetClassLoader();
+      DCHECK(class_loader != nullptr);  // We do not use .bss GC roots for boot image.
       // Note that we emit the barrier before the compiled code stores the string as GC root.
       // This is OK as there is no suspend point point in between.
       Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index be061be..a61a187 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -33,8 +33,7 @@
 namespace art {
 
 InternTable::InternTable()
-    : images_added_to_intern_table_(false),
-      log_new_roots_(false),
+    : log_new_roots_(false),
       weak_intern_condition_("New intern condition", *Locks::intern_table_lock_),
       weak_root_state_(gc::kWeakRootStateNormal) {
 }
@@ -181,57 +180,8 @@
     const ImageSection& section = header->GetImageSection(ImageHeader::kSectionInternedStrings);
     if (section.Size() > 0) {
       AddTableFromMemoryLocked(image_space->Begin() + section.Offset());
-    } else {
-      // TODO: Delete this logic?
-      mirror::Object* root = header->GetImageRoot(ImageHeader::kDexCaches);
-      mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
-      for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
-        mirror::DexCache* dex_cache = dex_caches->Get(i);
-        const size_t num_strings = dex_cache->NumStrings();
-        for (size_t j = 0; j < num_strings; ++j) {
-          mirror::String* image_string = dex_cache->GetResolvedString(j);
-          if (image_string != nullptr) {
-            mirror::String* found = LookupStrongLocked(image_string);
-            if (found == nullptr) {
-              InsertStrong(image_string);
-            } else {
-              DCHECK_EQ(found, image_string);
-            }
-          }
-        }
-      }
     }
   }
-  images_added_to_intern_table_ = true;
-}
-
-mirror::String* InternTable::LookupStringFromImage(mirror::String* s) {
-  DCHECK(!images_added_to_intern_table_);
-  const std::vector<gc::space::ImageSpace*>& image_spaces =
-      Runtime::Current()->GetHeap()->GetBootImageSpaces();
-  if (image_spaces.empty()) {
-    return nullptr;  // No image present.
-  }
-  const std::string utf8 = s->ToModifiedUtf8();
-  for (gc::space::ImageSpace* image_space : image_spaces) {
-    mirror::Object* root = image_space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
-    mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
-    for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
-      mirror::DexCache* dex_cache = dex_caches->Get(i);
-      const DexFile* dex_file = dex_cache->GetDexFile();
-      // Binary search the dex file for the string index.
-      const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str());
-      if (string_id != nullptr) {
-        uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
-        // GetResolvedString() contains a RB.
-        mirror::String* image_string = dex_cache->GetResolvedString(string_idx);
-        if (image_string != nullptr) {
-          return image_string;
-        }
-      }
-    }
-  }
-  return nullptr;
 }
 
 void InternTable::BroadcastForNewInterns() {
@@ -303,13 +253,6 @@
     }
     return weak;
   }
-  // Check the image for a match.
-  if (!images_added_to_intern_table_) {
-    mirror::String* const image_string = LookupStringFromImage(s);
-    if (image_string != nullptr) {
-      return is_strong ? InsertStrong(image_string) : InsertWeak(image_string);
-    }
-  }
   // No match in the strong table or the weak table. Insert into the strong / weak table.
   return is_strong ? InsertStrong(s) : InsertWeak(s);
 }
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 184fbdc..30ff55d 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -238,8 +238,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
 
   // Transaction rollback access.
-  mirror::String* LookupStringFromImage(mirror::String* s)
-      REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
   mirror::String* InsertStrongFromTransaction(mirror::String* s)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
   mirror::String* InsertWeakFromTransaction(mirror::String* s)
@@ -260,7 +258,6 @@
   void WaitUntilAccessible(Thread* self)
       REQUIRES(Locks::intern_table_lock_) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool images_added_to_intern_table_ GUARDED_BY(Locks::intern_table_lock_);
   bool log_new_roots_ GUARDED_BY(Locks::intern_table_lock_);
   ConditionVariable weak_intern_condition_ GUARDED_BY(Locks::intern_table_lock_);
   // Since this contains (strong) roots, they need a read barrier to
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index f164a92..c14b616 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -959,7 +959,7 @@
     DCHECK(!error_msg->empty());
     return false;
   }
-  bool loaded = elf_file_->Load(executable, low_4gb, error_msg);
+  bool loaded = elf_file_->Load(file, executable, low_4gb, error_msg);
   DCHECK(loaded || !error_msg->empty());
   return loaded;
 }
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9c0d2db..baa4046 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -829,7 +829,7 @@
     if (file.get() == nullptr) {
       return false;
     }
-    std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(),
+    std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.get(),
                                                     false /* writable */,
                                                     false /* program_header_only */,
                                                     false /* low_4gb */,
@@ -1165,10 +1165,6 @@
       ScopedTrace trace2("AddImageStringsToTable");
       GetInternTable()->AddImagesStringsToTable(heap_->GetBootImageSpaces());
     }
-    {
-      ScopedTrace trace2("MoveImageClassesToClassTable");
-      GetClassLinker()->AddBootImageClassesToClassTable();
-    }
   } else {
     std::vector<std::string> dex_filenames;
     Split(boot_class_path_string_, ':', &dex_filenames);