Add more read barriers to the class linker.

This change makes it possible to concurrently scan the remaining roots
in the class linker (the non-class-table roots that are visited by
ClassLinker::VisitRoots()) by adding read barriers.

Bug: 12687968
Change-Id: I66fecf7a303eee7537429e018f38da8270b18c67
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ca1239f..6e5f19a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -263,7 +263,11 @@
   }
   mirror::String* string = obj->AsString();
   const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
-  for (DexCache* dex_cache : Runtime::Current()->GetClassLinker()->GetDexCaches()) {
+  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(string->GetLength() == 0)) {
@@ -316,7 +320,10 @@
 
   // Clear references to removed classes from the DexCaches.
   ArtMethod* resolution_method = runtime->GetResolutionMethod();
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+    DexCache* dex_cache = class_linker->GetDexCache(idx);
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
       Class* klass = dex_cache->GetResolvedType(i);
       if (klass != NULL && !IsImageClass(klass)) {
@@ -408,13 +415,27 @@
   Handle<Class> object_array_class(hs.NewHandle(
       class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
 
-  // build an Object[] of all the DexCaches used in the source_space_
+  // build an Object[] of all the DexCaches used in the source_space_.
+  // Since we can't hold the dex lock when allocating the dex_caches
+  // ObjectArray, we lock the dex lock twice, first to get the number
+  // of dex caches first and then lock it again to copy the dex
+  // caches. We check that the number of dex caches does not change.
+  size_t dex_cache_count;
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    dex_cache_count = class_linker->GetDexCacheCount();
+  }
   Handle<ObjectArray<Object>> dex_caches(
       hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
-                                              class_linker->GetDexCaches().size())));
-  int i = 0;
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
-    dex_caches->Set<false>(i++, dex_cache);
+                                              dex_cache_count)));
+  CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array.";
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
+        << "The number of dex caches changed.";
+    for (size_t i = 0; i < dex_cache_count; ++i) {
+      dex_caches->Set<false>(i, class_linker->GetDexCache(i));
+    }
   }
 
   // build an Object[] of the roots needed to restore the runtime