Revert "Change dex caches to be weak roots"

This reverts commit 3ae6b1d42523bb2a0ddb5edff1aaf05b592f28f4.
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 83f391d..80387f2 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -31,7 +31,7 @@
 namespace art {
 
 inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) {
-  return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile(), false);
+  return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
 }
 
 inline mirror::ClassLoader* CompilerDriver::GetClassLoader(ScopedObjectAccess& soa,
@@ -87,7 +87,7 @@
 }
 
 inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) {
-  return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file, false);
+  return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
 }
 
 inline ArtField* CompilerDriver::ResolveField(
@@ -339,7 +339,7 @@
     // Sharpen a virtual call into a direct call. The method_idx is into referrer's
     // dex cache, check that this resolved method is where we expect it.
     CHECK_EQ(target_method->dex_file, mUnit->GetDexFile());
-    DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile(), false));
+    DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
     CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(
         target_method->dex_method_index, pointer_size),
              resolved_method) << PrettyMethod(resolved_method);
@@ -369,7 +369,7 @@
           nullptr, kVirtual);
     } else {
       StackHandleScope<1> hs(soa.Self());
-      auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(*devirt_target->dex_file)));
+      auto target_dex_cache(hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
       called_method = class_linker->ResolveMethod(
           *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache,
           class_loader, nullptr, kVirtual);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 89668f2..fb3af2d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -940,7 +940,7 @@
       uint16_t exception_type_idx = exception_type.first;
       const DexFile* dex_file = exception_type.second;
       StackHandleScope<2> hs2(self);
-      Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file)));
+      Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->FindDexCache(*dex_file)));
       Handle<mirror::Class> klass(hs2.NewHandle(
           class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
                                     NullHandle<mirror::ClassLoader>())));
@@ -1174,8 +1174,7 @@
       IsImageClass(dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) {
     {
       ScopedObjectAccess soa(Thread::Current());
-      mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
-          dex_file, false);
+      mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
       mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
       if (resolved_class == nullptr) {
         // Erroneous class.
@@ -1200,9 +1199,9 @@
     // We resolve all const-string strings when building for the image.
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file, false)));
-    class_linker->ResolveString(dex_file, string_idx, dex_cache);
+    Handle<mirror::DexCache> dex_cache(
+        hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(dex_file)));
+    Runtime::Current()->GetClassLinker()->ResolveString(dex_file, string_idx, dex_cache);
     result = true;
   }
   if (result) {
@@ -1227,7 +1226,7 @@
     *equals_referrers_class = false;
   }
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file, false);
+  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
@@ -1264,8 +1263,7 @@
                                                             const DexFile& dex_file,
                                                             uint32_t type_idx) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
-      dex_file, false);
+  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
@@ -1294,7 +1292,7 @@
                                         uintptr_t* direct_type_ptr, bool* out_is_finalizable) {
   ScopedObjectAccess soa(Thread::Current());
   Runtime* runtime = Runtime::Current();
-  mirror::DexCache* dex_cache = runtime->GetClassLinker()->FindDexCache(dex_file, false);
+  mirror::DexCache* dex_cache = runtime->GetClassLinker()->FindDexCache(dex_file);
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
     return false;
@@ -1423,7 +1421,7 @@
   {
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache_handle(
-        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile(), false)));
+        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
     Handle<mirror::ClassLoader> class_loader_handle(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
     resolved_field =
@@ -1473,7 +1471,7 @@
   {
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache_handle(
-        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile(), false)));
+        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
     Handle<mirror::ClassLoader> class_loader_handle(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
     resolved_field =
@@ -1659,7 +1657,7 @@
   // Try to resolve the method and compiling method's class.
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache(
-      hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile(), false)));
+      hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
       soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
   uint32_t method_idx = target_method->dex_method_index;
@@ -1911,7 +1909,7 @@
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file, false)));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
     // Resolve the class.
     mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
                                                      class_loader);
@@ -2004,7 +2002,7 @@
     ClassLinker* class_linker = manager_->GetClassLinker();
     const DexFile& dex_file = *manager_->GetDexFile();
     StackHandleScope<2> hs(soa.Self());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(dex_file)));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager_->GetClassLoader())));
     mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
@@ -2090,7 +2088,7 @@
        * This is to ensure the class is structurally sound for compilation. An unsound class
        * will be rejected by the verifier and later skipped during compilation in the compiler.
        */
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file, false)));
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
       std::string error_msg;
       if (verifier::MethodVerifier::VerifyClass(soa.Self(), &dex_file, dex_cache, class_loader,
                                                 &class_def, true, &error_msg) ==
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index dbd3366..93897aa 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -70,6 +70,7 @@
 
 // Separate objects into multiple bins to optimize dirty memory use.
 static constexpr bool kBinObjects = true;
+static constexpr bool kComputeEagerResolvedStrings = false;
 
 static void CheckNoDexObjectsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED)
     SHARED_REQUIRES(Locks::mutator_lock_) {
@@ -89,6 +90,11 @@
     PruneNonImageClasses();  // Remove junk
     ComputeLazyFieldsForImageClasses();  // Add useful information
 
+    // Calling this can in theory fill in some resolved strings. However, in practice it seems to
+    // never resolve any.
+    if (kComputeEagerResolvedStrings) {
+      ComputeEagerResolvedStrings();
+    }
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   }
   gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -296,15 +302,11 @@
 
 void ImageWriter::PrepareDexCacheArraySlots() {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Thread* const self = Thread::Current();
-  ReaderMutexLock mu(self, *class_linker->DexLock());
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
   uint32_t size = 0u;
-  for (jobject weak_root : class_linker->GetDexCaches()) {
-    mirror::DexCache* dex_cache =
-        down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache == nullptr) {
-      continue;
-    }
+  for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+    DexCache* dex_cache = class_linker->GetDexCache(idx);
     const DexFile* dex_file = dex_cache->GetDexFile();
     dex_cache_array_starts_.Put(dex_file, size);
     DexCacheArraysLayout layout(target_ptr_size_, dex_file);
@@ -552,6 +554,39 @@
   class_linker->VisitClassesWithoutClassesLock(&visitor);
 }
 
+void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED) {
+  if (!obj->GetClass()->IsStringClass()) {
+    return;
+  }
+  mirror::String* string = obj->AsString();
+  const uint16_t* utf16_string = string->GetValue();
+  size_t utf16_length = static_cast<size_t>(string->GetLength());
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t i = 0; i < dex_cache_count; ++i) {
+    DexCache* dex_cache = class_linker->GetDexCache(i);
+    const DexFile& dex_file = *dex_cache->GetDexFile();
+    const DexFile::StringId* string_id;
+    if (UNLIKELY(utf16_length == 0)) {
+      string_id = dex_file.FindStringId("");
+    } else {
+      string_id = dex_file.FindStringId(utf16_string, utf16_length);
+    }
+    if (string_id != nullptr) {
+      // This string occurs in this dex file, assign the dex cache entry.
+      uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
+      if (dex_cache->GetResolvedString(string_idx) == nullptr) {
+        dex_cache->SetResolvedString(string_idx, string);
+      }
+    }
+  }
+}
+
+void ImageWriter::ComputeEagerResolvedStrings() {
+  Runtime::Current()->GetHeap()->VisitObjects(ComputeEagerResolvedStringsCallback, this);
+}
+
 bool ImageWriter::IsImageClass(Class* klass) {
   if (klass == nullptr) {
     return false;
@@ -596,14 +631,16 @@
 
   // Clear references to removed classes from the DexCaches.
   const ArtMethod* resolution_method = runtime->GetResolutionMethod();
-
-  ScopedAssertNoThreadSuspension sa(self, __FUNCTION__);
-  ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);  // For ClassInClassTable
-  ReaderMutexLock mu2(self, *class_linker->DexLock());
-  for (jobject weak_root : class_linker->GetDexCaches()) {
-    mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache == nullptr) {
-      continue;
+  size_t dex_cache_count;
+  {
+    ReaderMutexLock mu(self, *class_linker->DexLock());
+    dex_cache_count = class_linker->GetDexCacheCount();
+  }
+  for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+    DexCache* dex_cache;
+    {
+      ReaderMutexLock mu(self, *class_linker->DexLock());
+      dex_cache = class_linker->GetDexCache(idx);
     }
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
       Class* klass = dex_cache->GetResolvedType(i);
@@ -725,12 +762,8 @@
     ReaderMutexLock mu(self, *class_linker->DexLock());
     CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
         << "The number of dex caches changed.";
-    size_t i = 0;
-    for (jobject weak_root : class_linker->GetDexCaches()) {
-      mirror::DexCache* dex_cache =
-          down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-      dex_caches->Set<false>(i, dex_cache);
-      ++i;
+    for (size_t i = 0; i < dex_cache_count; ++i) {
+      dex_caches->Set<false>(i, class_linker->GetDexCache(i));
     }
   }
 
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 778521c..c8aa82d 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -225,6 +225,11 @@
   void ComputeLazyFieldsForImageClasses()
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  // Wire dex cache resolved strings to strings in the image to avoid runtime resolution.
+  void ComputeEagerResolvedStrings() SHARED_REQUIRES(Locks::mutator_lock_);
+  static void ComputeEagerResolvedStringsCallback(mirror::Object* obj, void* arg)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   // Remove unwanted classes from various roots.
   void PruneNonImageClasses() SHARED_REQUIRES(Locks::mutator_lock_);
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 0e0b224..64e7487 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -691,8 +691,6 @@
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-    // No thread suspension since dex_cache_ that may get invalidated if that occurs.
-    ScopedAssertNoThreadSuspension tsc(Thread::Current(), __FUNCTION__);
     if (compiled_method != nullptr) {  // ie. not an abstract method
       size_t file_offset = file_offset_;
       OutputStream* out = out_;
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 824f28e..97b9972 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -362,7 +362,7 @@
     if (kIsDebugBuild) {
       ScopedObjectAccess soa(Thread::Current());
       ClassLinker* cl = Runtime::Current()->GetClassLinker();
-      mirror::DexCache* dex_cache = cl->FindDexCache(instr->AsInvoke()->GetDexFile(), false);
+      mirror::DexCache* dex_cache = cl->FindDexCache(instr->AsInvoke()->GetDexFile());
       ArtMethod* method = dex_cache->GetResolvedMethod(
           instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
       DCHECK(method != nullptr);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 07cf88c..99736e9 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1207,14 +1207,6 @@
     oat_file_.reset();
   }
 
-  void Shutdown() {
-    ScopedObjectAccess soa(Thread::Current());
-    for (jobject dex_cache : dex_caches_) {
-      soa.Env()->DeleteLocalRef(dex_cache);
-    }
-    dex_caches_.clear();
-  }
-
   // Set up the environment for compilation. Includes starting the runtime and loading/opening the
   // boot class path.
   bool Setup() {
@@ -1328,9 +1320,8 @@
       compiled_methods_.reset(nullptr);  // By default compile everything.
     }
 
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
     if (boot_image_option_.empty()) {
-      dex_files_ = class_linker->GetBootClassPath();
+      dex_files_ = Runtime::Current()->GetClassLinker()->GetBootClassPath();
     } else {
       if (dex_filenames_.empty()) {
         ATRACE_BEGIN("Opening zip archive from file descriptor");
@@ -1383,15 +1374,11 @@
         }
       }
     }
-    // Ensure opened dex files are writable for dex-to-dex transformations. Also ensure that
-    // the dex caches stay live since we don't want class unloading to occur during compilation.
+    // Ensure opened dex files are writable for dex-to-dex transformations.
     for (const auto& dex_file : dex_files_) {
       if (!dex_file->EnableWrite()) {
         PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
       }
-      ScopedObjectAccess soa(self);
-      dex_caches_.push_back(soa.AddLocalReference<jobject>(
-          class_linker->RegisterDexFile(*dex_file)));
     }
 
     // If we use a swap file, ensure we are above the threshold to make it necessary.
@@ -1436,7 +1423,6 @@
     // Handle and ClassLoader creation needs to come after Runtime::Create
     jobject class_loader = nullptr;
     Thread* self = Thread::Current();
-
     if (!boot_image_option_.empty()) {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       OpenClassPathFiles(runtime_->GetClassPathString(), dex_files_, &class_path_files_);
@@ -1971,7 +1957,6 @@
   bool is_host_;
   std::string android_root_;
   std::vector<const DexFile*> dex_files_;
-  std::vector<jobject> dex_caches_;
   std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
   std::unique_ptr<CompilerDriver> driver_;
   std::vector<std::string> verbose_methods_;
@@ -2122,15 +2107,11 @@
     return EXIT_FAILURE;
   }
 
-  bool result;
   if (dex2oat.IsImage()) {
-    result = CompileImage(dex2oat);
+    return CompileImage(dex2oat);
   } else {
-    result = CompileApp(dex2oat);
+    return CompileApp(dex2oat);
   }
-
-  dex2oat.Shutdown();
-  return result;
 }
 }  // namespace art
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index c553a18..a2aa77e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -827,15 +827,11 @@
       DumpDexCode(vios->Stream(), dex_file, code_item);
     }
 
-    std::unique_ptr<StackHandleScope<1>> hs;
     std::unique_ptr<verifier::MethodVerifier> verifier;
     if (Runtime::Current() != nullptr) {
-      // We need to have the handle scope stay live until after the verifier since the verifier has
-      // a handle to the dex cache from hs.
-      hs.reset(new StackHandleScope<1>(Thread::Current()));
       vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
       ScopedIndentation indent2(vios);
-      verifier.reset(DumpVerifier(vios, hs.get(),
+      verifier.reset(DumpVerifier(vios,
                                   dex_method_idx, &dex_file, class_def, code_item,
                                   method_access_flags));
     }
@@ -1408,7 +1404,6 @@
   }
 
   verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
-                                         StackHandleScope<1>* hs,
                                          uint32_t dex_method_idx,
                                          const DexFile* dex_file,
                                          const DexFile::ClassDef& class_def,
@@ -1416,8 +1411,9 @@
                                          uint32_t method_access_flags) {
     if ((method_access_flags & kAccNative) == 0) {
       ScopedObjectAccess soa(Thread::Current());
+      StackHandleScope<1> hs(soa.Self());
       Handle<mirror::DexCache> dex_cache(
-          hs->NewHandle(Runtime::Current()->GetClassLinker()->RegisterDexFile(*dex_file)));
+          hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
       DCHECK(options_.class_loader_ != nullptr);
       return verifier::MethodVerifier::VerifyMethodAndDump(
           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
@@ -1618,13 +1614,10 @@
       dex_cache_arrays_.clear();
       {
         ReaderMutexLock mu(self, *class_linker->DexLock());
-        for (jobject weak_root : class_linker->GetDexCaches()) {
-          mirror::DexCache* dex_cache =
-              down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-          if (dex_cache != nullptr) {
-            dex_cache_arrays_.insert(dex_cache->GetResolvedFields());
-            dex_cache_arrays_.insert(dex_cache->GetResolvedMethods());
-          }
+        for (size_t i = 0; i < class_linker->GetDexCacheCount(); ++i) {
+          auto* dex_cache = class_linker->GetDexCache(i);
+          dex_cache_arrays_.insert(dex_cache->GetResolvedFields());
+          dex_cache_arrays_.insert(dex_cache->GetResolvedMethods());
         }
       }
       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 5f2caef..848c904 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -64,7 +64,6 @@
   kJdwpSocketLock,
   kRegionSpaceRegionLock,
   kTransactionLogLock,
-  kJniWeakGlobalsLock,
   kReferenceQueueSoftReferencesLock,
   kReferenceQueuePhantomReferencesLock,
   kReferenceQueueFinalizerReferencesLock,
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index d2dbff6..11901b3 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -195,6 +195,12 @@
   return klass;
 }
 
+inline mirror::DexCache* ClassLinker::GetDexCache(size_t idx) {
+  dex_lock_.AssertSharedHeld(Thread::Current());
+  DCHECK(idx < dex_caches_.size());
+  return dex_caches_[idx].Read();
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3b505e6..b074dec 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -273,6 +273,7 @@
       array_iftable_(nullptr),
       find_array_class_cache_next_victim_(0),
       init_done_(false),
+      log_new_dex_caches_roots_(false),
       log_new_class_table_roots_(false),
       intern_table_(intern_table),
       quick_resolution_trampoline_(nullptr),
@@ -331,12 +332,6 @@
   java_lang_Class->SetSuperClass(java_lang_Object.Get());
   mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self);
 
-  java_lang_Object->SetObjectSize(sizeof(mirror::Object));
-  runtime->SetSentinel(heap->AllocObject<true>(self,
-                                               java_lang_Object.Get(),
-                                               java_lang_Object->GetObjectSize(),
-                                               VoidFunctor()));
-
   // Object[] next to hold class roots.
   Handle<mirror::Class> object_array_class(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(),
@@ -1148,11 +1143,11 @@
   quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
   quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
   quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge();
-  StackHandleScope<2> hs(self);
   mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
-  Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
-      hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
+  mirror::ObjectArray<mirror::DexCache>* dex_caches =
+      dex_caches_object->AsObjectArray<mirror::DexCache>();
 
+  StackHandleScope<1> hs(self);
   Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
           space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
           AsObjectArray<mirror::Class>()));
@@ -1162,13 +1157,6 @@
   // as being Strings or not
   mirror::String::SetClass(GetClassRoot(kJavaLangString));
 
-  mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
-  java_lang_Object->SetObjectSize(sizeof(mirror::Object));
-  Runtime::Current()->SetSentinel(Runtime::Current()->GetHeap()->AllocObject<true>(self,
-                                                          java_lang_Object,
-                                                          java_lang_Object->GetObjectSize(),
-                                                          VoidFunctor()));
-
   CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
            static_cast<uint32_t>(dex_caches->GetLength()));
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
@@ -1262,6 +1250,7 @@
 }
 
 bool ClassLinker::ClassInClassTable(mirror::Class* klass) {
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   ClassTable* const class_table = ClassTableForClassLoader(klass->GetClassLoader());
   return class_table != nullptr && class_table->Contains(klass);
 }
@@ -1318,6 +1307,27 @@
 // mapped image.
 void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) {
   class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
+  Thread* const self = Thread::Current();
+  {
+    ReaderMutexLock mu(self, dex_lock_);
+    if ((flags & kVisitRootFlagAllRoots) != 0) {
+      for (GcRoot<mirror::DexCache>& dex_cache : dex_caches_) {
+        dex_cache.VisitRoot(visitor, RootInfo(kRootVMInternal));
+      }
+    } else if ((flags & kVisitRootFlagNewRoots) != 0) {
+      for (size_t index : new_dex_cache_roots_) {
+        dex_caches_[index].VisitRoot(visitor, RootInfo(kRootVMInternal));
+      }
+    }
+    if ((flags & kVisitRootFlagClearRootLog) != 0) {
+      new_dex_cache_roots_.clear();
+    }
+    if ((flags & kVisitRootFlagStartLoggingNewRoots) != 0) {
+      log_new_dex_caches_roots_ = true;
+    } else if ((flags & kVisitRootFlagStopLoggingNewRoots) != 0) {
+      log_new_dex_caches_roots_ = false;
+    }
+  }
   VisitClassRoots(visitor, flags);
   array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   for (GcRoot<mirror::Class>& root : find_array_class_cache_) {
@@ -1692,6 +1702,7 @@
                 long_array->GetWithoutChecks(j)));
             const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
             if (dex_class_def != nullptr) {
+              RegisterDexFile(*cp_dex_file);
               mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader,
                                                  *cp_dex_file, *dex_class_def);
               if (klass == nullptr) {
@@ -1837,7 +1848,7 @@
     CHECK(self->IsExceptionPending());  // Expect an OOME.
     return nullptr;
   }
-  klass->SetDexCache(RegisterDexFile(dex_file));
+  klass->SetDexCache(FindDexCache(dex_file));
 
   SetupClass(dex_file, dex_class_def, klass, class_loader.Get());
 
@@ -2471,52 +2482,58 @@
   RegisterDexFile(dex_file, dex_cache);
 }
 
+bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) {
+  dex_lock_.AssertSharedHeld(Thread::Current());
+  for (GcRoot<mirror::DexCache>& root : dex_caches_) {
+    mirror::DexCache* dex_cache = root.Read();
+    if (dex_cache->GetDexFile() == &dex_file) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) {
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
+  return IsDexFileRegisteredLocked(dex_file);
+}
+
 void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
                                         Handle<mirror::DexCache> dex_cache) {
-  Thread* const self = Thread::Current();
-  dex_lock_.AssertExclusiveHeld(self);
+  dex_lock_.AssertExclusiveHeld(Thread::Current());
   CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
       << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
-  // Clean up pass to remove null dex caches.
-  // Null dex caches can occur due to class unloading and we are lazily removing null entries.
-  JavaVMExt* const vm = self->GetJniEnv()->vm;
-  for (auto it = dex_caches_.begin(); it != dex_caches_.end();) {
-    mirror::Object* dex_cache_root = self->DecodeJObject(*it);
-    if (dex_cache_root == nullptr) {
-      vm->DeleteWeakGlobalRef(self, *it);
-      it = dex_caches_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-  dex_caches_.push_back(vm->AddWeakGlobalRef(self, dex_cache.Get()));
+  dex_caches_.push_back(GcRoot<mirror::DexCache>(dex_cache.Get()));
   dex_cache->SetDexFile(&dex_file);
+  if (log_new_dex_caches_roots_) {
+    // TODO: This is not safe if we can remove dex caches.
+    new_dex_cache_roots_.push_back(dex_caches_.size() - 1);
+  }
 }
 
-mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file) {
+void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
   Thread* self = Thread::Current();
   {
     ReaderMutexLock mu(self, dex_lock_);
-    mirror::DexCache* dex_cache = FindDexCacheLocked(dex_file, true);
-    if (dex_cache != nullptr) {
-      return dex_cache;
+    if (IsDexFileRegisteredLocked(dex_file)) {
+      return;
     }
   }
   // Don't alloc while holding the lock, since allocation may need to
   // suspend all threads and another thread may need the dex_lock_ to
   // get to a suspend point.
   StackHandleScope<1> hs(self);
-  Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
-  CHECK(h_dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
-                                      << dex_file.GetLocation();
-  WriterMutexLock mu(self, dex_lock_);
-  mirror::DexCache* dex_cache = FindDexCacheLocked(dex_file, true);
-  if (dex_cache != nullptr) {
-    return dex_cache;
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+  CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
+                                    << dex_file.GetLocation();
+  {
+    WriterMutexLock mu(self, dex_lock_);
+    if (IsDexFileRegisteredLocked(dex_file)) {
+      return;
+    }
+    RegisterDexFileLocked(dex_file, dex_cache);
   }
-  RegisterDexFileLocked(dex_file, h_dex_cache);
-  return h_dex_cache.Get();
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file,
@@ -2525,44 +2542,36 @@
   RegisterDexFileLocked(dex_file, dex_cache);
 }
 
-mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file, bool allow_failure) {
-  Thread* const self = Thread::Current();
-  ReaderMutexLock mu(self, dex_lock_);
-  return FindDexCacheLocked(dex_file, allow_failure);
-}
-
-mirror::DexCache* ClassLinker::FindDexCacheLocked(const DexFile& dex_file, bool allow_failure) {
-  Thread* const self = Thread::Current();
+mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) {
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   // Search assuming unique-ness of dex file.
-  for (jobject weak_root : dex_caches_) {
-    mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache != nullptr && dex_cache->GetDexFile() == &dex_file) {
+  for (size_t i = 0; i != dex_caches_.size(); ++i) {
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    if (dex_cache->GetDexFile() == &dex_file) {
       return dex_cache;
     }
   }
-  if (allow_failure) {
-    return nullptr;
-  }
+  // Search matching by location name.
   std::string location(dex_file.GetLocation());
-  // Failure, dump diagnostic and abort.
-  for (jobject weak_root : dex_caches_) {
-    mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache != nullptr) {
-      LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation();
+  for (size_t i = 0; i != dex_caches_.size(); ++i) {
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    if (dex_cache->GetDexFile()->GetLocation() == location) {
+      return dex_cache;
     }
   }
+  // Failure, dump diagnostic and abort.
+  for (size_t i = 0; i != dex_caches_.size(); ++i) {
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
+  }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
   UNREACHABLE();
 }
 
 void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) {
-  Thread* const self = Thread::Current();
-  ReaderMutexLock mu(self, dex_lock_);
-  for (jobject weak_root : dex_caches_) {
-    mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache != nullptr) {
-      dex_cache->Fixup(resolution_method, image_pointer_size_);
-    }
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
+  for (auto& dex_cache : dex_caches_) {
+    dex_cache.Read()->Fixup(resolution_method, image_pointer_size_);
   }
 }
 
@@ -3398,13 +3407,11 @@
   DCHECK(proxy_class->IsProxyClass());
   DCHECK(proxy_method->IsProxyMethod());
   {
-    Thread* const self = Thread::Current();
-    ReaderMutexLock mu(self, dex_lock_);
+    ReaderMutexLock mu(Thread::Current(), dex_lock_);
     // Locate the dex cache of the original interface/Object
-    for (jobject weak_root : dex_caches_) {
-      mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-      if (dex_cache != nullptr &&
-          proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
+    for (const GcRoot<mirror::DexCache>& root : dex_caches_) {
+      auto* dex_cache = root.Read();
+      if (proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
         ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
             proxy_method->GetDexMethodIndex(), image_pointer_size_);
         CHECK(resolved_method != nullptr);
@@ -5871,6 +5878,11 @@
   // We could move the jobject to the callers, but all call-sites do this...
   ScopedObjectAccessUnchecked soa(self);
 
+  // Register the dex files.
+  for (const DexFile* dex_file : dex_files) {
+    RegisterDexFile(*dex_file);
+  }
+
   // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
   StackHandleScope<10> hs(self);
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index cc56e8b..fbf4035 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -278,7 +278,7 @@
   void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
-  mirror::DexCache* RegisterDexFile(const DexFile& dex_file)
+  void RegisterDexFile(const DexFile& dex_file)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
   void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -309,7 +309,9 @@
   void VisitRoots(RootVisitor* visitor, VisitRootFlags flags)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  mirror::DexCache* FindDexCache(const DexFile& dex_file, bool allow_failure = false)
+  mirror::DexCache* FindDexCache(const DexFile& dex_file)
+      REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsDexFileRegistered(const DexFile& dex_file)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
   void FixupDexCaches(ArtMethod* resolution_method)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -469,7 +471,7 @@
 
   // Used by image writer for checking.
   bool ClassInClassTable(mirror::Class* klass)
-      REQUIRES(Locks::classlinker_classes_lock_)
+      REQUIRES(!Locks::classlinker_classes_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   ArtMethod* CreateRuntimeMethod();
@@ -559,9 +561,8 @@
 
   void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       REQUIRES(dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
-  mirror::DexCache* FindDexCacheLocked(const DexFile& dex_file, bool allow_failure)
-      REQUIRES(dex_lock_)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file)
+      SHARED_REQUIRES(dex_lock_, Locks::mutator_lock_);
 
   bool InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_run_clinit,
                        bool can_init_parents)
@@ -630,9 +631,7 @@
   size_t GetDexCacheCount() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) {
     return dex_caches_.size();
   }
-  const std::list<jobject>& GetDexCaches() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) {
-    return dex_caches_;
-  }
+  mirror::DexCache* GetDexCache(size_t idx) SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_);
 
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
       REQUIRES(!dex_lock_);
@@ -703,9 +702,8 @@
   std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
 
   mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  // JNI weak globals to allow dex caches to get unloaded. We lazily delete weak globals when we
-  // register new dex files.
-  std::list<jobject> dex_caches_ GUARDED_BY(dex_lock_);
+  std::vector<size_t> new_dex_cache_roots_ GUARDED_BY(dex_lock_);
+  std::vector<GcRoot<mirror::DexCache>> dex_caches_ GUARDED_BY(dex_lock_);
   std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
 
   // This contains the class laoders which have class tables. It is populated by
@@ -738,6 +736,7 @@
   size_t find_array_class_cache_next_victim_;
 
   bool init_done_;
+  bool log_new_dex_caches_roots_ GUARDED_BY(dex_lock_);
   bool log_new_class_table_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
 
   InternTable* intern_table_;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 56c5d1a..5f9e413 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -551,8 +551,7 @@
   }
 
   Thread* self = Thread::Current();
-  jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,
-                                                                                     class_path);
+  jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,                                                                                   class_path);
   self->SetClassLoaderOverride(class_loader);
   return class_loader;
 }
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 2fd0517..9d41018 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -373,7 +373,7 @@
       globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
       libraries_(new Libraries),
       unchecked_functions_(&gJniInvokeInterface),
-      weak_globals_lock_("JNI weak global reference table lock", kJniWeakGlobalsLock),
+      weak_globals_lock_("JNI weak global reference table lock"),
       weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
       allow_new_weak_globals_(true),
       weak_globals_add_condition_("weak globals add condition", weak_globals_lock_) {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 9bd320c..4f97d20 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -171,7 +171,7 @@
     if (array == nullptr) {
       ScopedObjectAccess soa(env);
       for (auto& dex_file : dex_files) {
-        if (Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file, true) != nullptr) {
+        if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
           dex_file.release();
         }
       }
@@ -209,7 +209,7 @@
   // TODO: The Runtime should support unloading of classes and freeing of the
   // dex files for those unloaded classes rather than leaking dex files here.
   for (auto& dex_file : *dex_files) {
-    if (Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file, true) == nullptr) {
+    if (!Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
       delete dex_file;
     }
   }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 5a9c43b..9ea339a 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -425,16 +425,14 @@
 static void PreloadDexCachesStatsFilled(DexCacheStats* filled)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   if (!kPreloadDexCachesCollectStats) {
-    return;
+      return;
   }
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
+  for (size_t i = 0; i< boot_class_path.size(); i++) {
+    const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != nullptr);
-    mirror::DexCache* const dex_cache = class_linker->FindDexCache(*dex_file, true);
-    // If dex cache was deallocated, just continue.
-    if (dex_cache == nullptr) {
-      continue;
-    }
+    mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
     for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
       mirror::String* string = dex_cache->GetResolvedString(j);
       if (string != nullptr) {
@@ -448,7 +446,7 @@
       }
     }
     for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
-      ArtField* field = class_linker->GetResolvedField(j, dex_cache);
+      ArtField* field = linker->GetResolvedField(j, dex_cache);
       if (field != nullptr) {
         filled->num_fields++;
       }
@@ -492,11 +490,11 @@
   }
 
   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
-  for (size_t i = 0; i < boot_class_path.size(); i++) {
+  for (size_t i = 0; i< boot_class_path.size(); i++) {
     const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != nullptr);
     StackHandleScope<1> hs(soa.Self());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->RegisterDexFile(*dex_file)));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
 
     if (kPreloadDexCachesStrings) {
       for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index bfa8c54..380e72b 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -20,7 +20,6 @@
 #include "runtime.h"
 
 #include "art_method.h"
-#include "class_linker.h"
 #include "read_barrier-inl.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 49451ad..1912314 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -791,12 +791,6 @@
   return failure_count;
 }
 
-void Runtime::SetSentinel(mirror::Object* sentinel) {
-  CHECK(sentinel_.Read() == nullptr);
-  CHECK(sentinel != nullptr);
-  sentinel_ = GcRoot<mirror::Object>(sentinel);
-}
-
 bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
   ATRACE_BEGIN("Runtime::Init");
   CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
@@ -1060,6 +1054,10 @@
 
   CHECK(class_linker_ != nullptr);
 
+  // Initialize the special sentinel_ value early.
+  sentinel_ = GcRoot<mirror::Object>(class_linker_->AllocObject(self));
+  CHECK(sentinel_.Read() != nullptr);
+
   verifier::MethodVerifier::Init();
 
   if (runtime_options.Exists(Opt::MethodTrace)) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index bd21db1..4577b75 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -568,9 +568,6 @@
     return fingerprint_;
   }
 
-  // Called from class linker.
-  void SetSentinel(mirror::Object* sentinel) SHARED_REQUIRES(Locks::mutator_lock_);
-
  private:
   static void InitPlatformSignalHandlers();
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 7579d8d..4393430 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -640,8 +640,7 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   for (auto& e : seen_methods) {
     DexIndexBitSet* bit_set = e.second;
-    // TODO: Visit trace methods as roots.
-    mirror::DexCache* dex_cache = class_linker->FindDexCache(*e.first, false);
+    mirror::DexCache* dex_cache = class_linker->FindDexCache(*e.first);
     for (uint32_t i = 0; i < bit_set->size(); ++i) {
       if ((*bit_set)[i]) {
         visited_methods->insert(dex_cache->GetResolvedMethod(i, sizeof(void*)));
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4f921bd..bba9c5e 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3407,7 +3407,6 @@
 ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
     uint32_t dex_method_idx, MethodType method_type) {
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
-  // LOG(INFO) << dex_file_->NumTypeIds() << " " << dex_file_->NumClassDefs();
   const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
   if (klass_type.IsConflict()) {
     std::string append(" in attempt to access method ");